We want to determine the extent to which the MIKK panel shows evidence of introgression with other medaka populations, specifically the allopatric Northern and Korean medaka strains, relative to sympatric Southern medaka strains.

Setup

library(here)
source(here::here("code", "scripts", "introgression", "source.R"))

Working directory

Working directory on EBI cluster: /hps/research1/birney/users/ian/mikk_paper

Create Singularity containers

container_dir=../sing_conts
# load Singularity (version 3.5.0)
module load singularity 

for package in $( echo r-base_4.0.4 bcftools_1.9 numpy_1.15.4 bash_3.0.22 bioconductor_3.12 ) ; do
  if [[ ! -f $container_dir/$package.sif ]]; then
    singularity build \
      --remote \
      $container_dir/$package.sif \
      envs/$package.def 
  fi ;
done

renv

Install all required packages (using r-base in Singularity container).

container_dir=../sing_conts
baseR=r-base_4.0.4

bsub -Is "singularity shell $container_dir/$baseR"
# Install all required packages
renv::restore()

Copy scripts from Simon Martin’s GitHub repo

wget -P code/scripts/introgression https://raw.githubusercontent.com/simonhmartin/genomics_general/master/ABBABABAwindows.py

wget -P code/scripts/introgression https://raw.githubusercontent.com/simonhmartin/genomics_general/master/genomics.py

Process multiple alignment data

Download from Ensembl

  • Ensembl 103: Only includes Oryzias latipes HdrR and Oryzias melastigma (Indian medaka).
  • Ensembl 102: Includes all target species. Use.

ftp://ftp.ensembl.org/pub/release-102/emf/ensembl-compara/multiple_alignments/50_fish.epo/README.50_fish.epo reads:

Alignments are grouped by japanese medaka hdrr chromosome, and then by coordinate system. Alignments containing duplications in japanese medaka hdrr are dumped once per duplicated segment. The files named .other.emf contain alignments that do not include any japanese medaka hdrr region. Each file contains up to 200 alignments.

ftp_dir=ftp://ftp.ensembl.org/pub/release-102/emf/ensembl-compara/multiple_alignments/50_fish.epo/
target_dir=../introgression/release-102

mkdir -p $target_dir/raw

# download, exlcuding *.other* files
wget -P $target_dir/raw $ftp_dir/* -R "*other*"

# unzip into new directory (excluding "other")
$target_dir/unzipped
mkdir -p $target_dir/unzipped

for i in $(find $target_dir/raw/50_fish.epo.[0-9]*); do
  name=$(basename $i | cut -f3,4 -d'.');
  bsub "zcat $i > $target_dir/unzipped/$name";
done
  • NOTE: File 6_2.emf is in a completely different format, with CIGAR strings instead of the normal SEQ, TREE, ID and DATA segments. It appears the file is corrupted.
  • The 6_2 file in release 101 is unaffected. Remove all release 102 chr 6 files and replace with release 101 files.
# remove release 102 files for chr 6
rm $target_dir/unzipped/6_*

# download chr 6 files from release 101
ftp_dir_101=ftp://ftp.ensembl.org/pub/release-101/emf/ensembl-compara/multiple_alignments/50_fish.epo/
target_dir_101=../introgression/release-101

mkdir -p $target_dir_101/raw

wget -P $target_dir_101/raw $ftp_dir_101/50_fish.epo.6_*

# unzip
mkdir -p $target_dir_101/unzipped

for i in $(find $target_dir_101/raw/*); do
  name=$(basename $i | cut -f3,4 -d'.') ;
  zcat $i > $target_dir_101/unzipped/$name ;
done

# copy over to release 102 directory
cp $target_dir_101/unzipped/* $target_dir/unzipped

Generate tree plot

Copy tree to file

tree_file=data/introgression/release_102_tree.txt

awk "NR==58,NR==205" $target_dir/raw/README.50_fish.epo \
  > $tree_file

Then manually edit $tree_file using regex to find spaces and replace them with "_": {bash} (?<=[a-z])( )(?=[a-z])

phylo_tree <- ape::read.tree(file = here::here("data", "introgression", "release_102_tree.txt"))

Full tree

# Colour all Oryzias
ids <- phylo_tree$tip.label[grep("Oryzias", phylo_tree$tip.label)]
# get indices of edges descending from MRCA (determined through trial and error)
oryzias_nodes <- seq(35, 42)
all_med_col <- ifelse(1:length(phylo_tree[["edge.length"]]) %in% oryzias_nodes, "#E84141", "black")
# set colours for tip labels
all_med_tip <- ifelse(phylo_tree$tip.label %in% ids, "#E84141", "black")
# plot
ape::plot.phylo(phylo_tree,
                use.edge.length = T,
                edge.color = all_med_col,
                tip.color = all_med_tip,
                font = 4)

# Save to repo
png(file= file.path(plots_dir, "tree_all.png"),
    width=22,
    height=25,
    units = "cm",
    res = 400)
ape::plot.phylo(phylo_tree,
                use.edge.length = T,
                edge.color = all_med_col,
                tip.color = all_med_tip,
                font = 4)
dev.off()

Oryzias only

New tree file created manually to extract Oryzias fishes only, and replace reference codes (e.g. “ASM223467v1”) with line names (e.g. “HdrR”).

in_file = here::here("data/introgression/release_102_tree_oryzias_only.txt")
# Read in
phylo_tree <- ape::read.tree(file = in_file)
# Set colours 
phylo_cols <- c("#55b6b0", "#f33a56", "#f3b61f", "#f6673a", "#631e68")
# Plot
ape::plot.phylo(phylo_tree,
                font = 4,
                tip.color = phylo_cols)

out_file = here::here(plots_dir, "tree_oryzias.png")
# Save
png(file=out_file,
    width=2700,
    height=1720,
    units = "px",
    res = 400)
ape::plot.phylo(phylo_tree,
                font = 4,
                tip.color = phylo_cols)
dev.off()

Add cross for ancestor

out_file = here::here(plots_dir, "tree_oryzias_with_ancestor.png")
in_file = here::here(plots_dir, "tree_oryzias.png")

tree_path = in_file

ggdraw() +
  draw_image(tree_path) +
  draw_label("x",
             x = 0.152,
             y = 0.52,
             fontface = "bold",
             color = "#f77cb5",
             size = 25)

ggsave(out_file,
    width=15.69,
    height=10,
    units = "cm",
    dpi = 400)
knitr::include_graphics(basename(out_file))

Divide by segment

target_dir=../introgression/release-102
segments_dir=$target_dir/segmented
date=20210312
script=code/scripts/introgression/20200907_extract-emf-segments.sh

mkdir -p $segments_dir

for i in $(find $target_dir/unzipped/* ); do
  # get basename
  bname=$(basename $i);
  bname_short=$(echo ${bname::-4} );
  # get chromosome
  chr=$(echo $bname | cut -f1 -d"_" );
  # make directory for each EMF file
  new_path=$(echo $segments_dir/$bname_short );
  if [ ! -d "$new_path" ]; then
    mkdir $new_path;
  fi
  # get segment count
  segment_count=$(grep "^DATA" $i | wc -l );
  # get segment start and end for each file
  for j in $(seq 1 $segment_count ); do
    bsub \
      -o ../log/$date\segment_$bname_short\_$j.out \
      -e ../log/$date\segment_$bname_short\_$j.err \
      "$script $i $j $new_path "
  done;  
done

# How many files?
find $segments_dir/*/*.data.txt | wc -l
# 8951
find $in_dir/*/*_1.data.txt | wc -l
# 4341
find $in_dir/*/*_-1.data.txt | wc -l
# 4610

Run analysis pipeline with snakemake

snmk_proj="introgression"

module load singularity
conda activate snakemake

snakemake \
 --jobs 5000 \
 --latency-wait 100 \
 --cluster-config code/snakemake/$snmk_proj/config/cluster.json \
 --cluster 'bsub -g /snakemake_bgenie -J {cluster.name} -n {cluster.n} -M {cluster.memory} -o {cluster.output} -e {cluster.error}' \
 --keep-going \
 --rerun-incomplete \
 --use-conda \
 --use-singularity \
 -s code/snakemake/$snmk_proj/Snakefile \
 -p

f statistic analysis

Read in data

data_file = here::here("data", "introgression", "20210315_f_stat_final.txt")
# Read in data
final_df <- read.table(data_file,
                       header = T,
                       sep = "\t",
                       as.is = T)

final_df <- final_df %>% 
  dplyr::mutate(across(P2,
                       ~factor(.x, levels = fish_order))) %>% 
  dplyr::mutate(chr = factor(chr, levels = chr_order))

knitr::kable(head(final_df))
P1 P2 P3 chr d_stat z_score admix_f f_ci_lower f_ci_upper
javanicus HdrR MIKK all 0.9072306 324.06735 0.7093524 0.6943606 0.7243441
javanicus HdrR MIKK 1 0.9422313 162.46960 0.8090713 0.7776743 0.8404682
javanicus HdrR MIKK 2 0.9128441 57.55129 0.7668972 0.6931469 0.8406474
javanicus HdrR MIKK 3 0.8869725 76.53532 0.6217246 0.5501172 0.6933320
javanicus HdrR MIKK 4 0.9318431 72.86056 0.7503846 0.6643958 0.8363734
javanicus HdrR MIKK 5 0.8879805 69.67407 0.6565419 0.5865893 0.7264945

Create DF with mean melastigma and javanicus

cor_df <- final_df %>% 
  # filter for when P1 is another Oryzias, and P2 
  dplyr::filter(P1 %in% c("javanicus", "melastigma") & P2 != "MIKK" & P3 == "MIKK") %>% 
  # pivot to put the admixture_f stat for melastigma and javanicus in the same row
  tidyr::pivot_wider(id_cols = c("P2", "chr"),
                     names_from = P1,
                     values_from = c(admix_f, f_ci_lower, f_ci_upper))

cor_df$chr <- as.character(cor_df$chr)
cor_df$chr <- ifelse(cor_df$chr == "all", "genome-wide", cor_df$chr)
chr_order_plot <- c(seq(1,24), "genome-wide")
cor_df$chr <- factor(cor_df$chr, levels = chr_order_plot)

cor_df_means <- cor_df %>%
  # apply across rows
  dplyr::rowwise() %>% 
  # get means for f and CIs
  dplyr::mutate(mean_f = mean(c(admix_f_javanicus, admix_f_melastigma)),
                mean_ci_upper = mean(c(f_ci_upper_javanicus, f_ci_upper_melastigma)),
                mean_ci_lower = mean(c(f_ci_lower_javanicus, f_ci_lower_melastigma))) %>% 
  # set stats at a maximum of 1
  dplyr::mutate(across(c("mean_f", "mean_ci_upper", "mean_ci_lower"),
                       ~dplyr::if_else(.x > 1,
                                       1,
                                       .x)))

knitr::kable(head(cor_df_means))
P2 chr admix_f_javanicus admix_f_melastigma f_ci_lower_javanicus f_ci_lower_melastigma f_ci_upper_javanicus f_ci_upper_melastigma mean_f mean_ci_upper mean_ci_lower
HdrR genome-wide 0.7093524 0.6860648 0.6943606 0.6712495 0.7243441 0.7008800 0.6977086 0.7126121 0.6828051
HdrR 1 0.8090713 0.7831495 0.7776743 0.7466954 0.8404682 0.8196036 0.7961104 0.8300359 0.7621849
HdrR 2 0.7668972 0.7621796 0.6931469 0.6999464 0.8406474 0.8244128 0.7645384 0.8325301 0.6965466
HdrR 3 0.6217246 0.5968322 0.5501172 0.5217981 0.6933320 0.6718664 0.6092784 0.6825992 0.5359576
HdrR 4 0.7503846 0.7399951 0.6643958 0.6811117 0.8363734 0.7988785 0.7451899 0.8176260 0.6727538
HdrR 5 0.6565419 0.6241430 0.5865893 0.5565435 0.7264945 0.6917426 0.6403425 0.7091186 0.5715664

Plot

fstat_plot = cor_df_means %>% 
  ggplot(aes(P2, mean_f, fill = P2)) +
    geom_col() +
    geom_errorbar(aes(ymin = mean_ci_lower,
                      ymax = mean_ci_upper),
                  position = position_dodge(0.9),
                  width = 0.25) +  
    guides(fill = F) +
    facet_wrap(~chr) +
    ylim(0,1) +
    ylab(expression(paste("Mean ", italic("f"), " statistic"))) +
    theme_cowplot(font_size = 8) +
    scale_fill_manual(values = pal_abba)

fstat_plot

out_file = here::here(plots_dir, "20210315_f_stat")

# PNG
ggsave(filename = paste(out_file, ".png", sep = ""),
       device = "png",
       width = 24.75,
       height = 19.5,
       units = "cm",
       dpi = 500)

# SVG
ggsave(filename = paste(out_file, ".svg", sep = ""),
       device = "svg",
       width = 24.75,
       height = 19.5,
       units = "cm")

Sliding windows ABBA BABA

Read in data

in_file = here::here("data", "introgression", "abba_sliding_final", "50000_100.txt")
# Read in data
df = readr::read_csv(in_file) %>% 
  dplyr::arrange(p1, p2, scaffold, start)

# Convert fd to 0 if D < 0
df$fd = ifelse(df$D < 0,
               0,
               df$fd)

# Change names
df = df %>% 
  dplyr::mutate(p2 = recode(df$p2, hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))

Plot

Standard

df %>% 
  dplyr::filter(p1 == "melastigma") %>% 
  ggplot() +
    geom_line(aes(mid, fd, colour = p2)) +
    facet_wrap(~scaffold, nrow = 24, ncol = 1) +
    scale_colour_manual(values = pal_abba) +
    theme_bw(base_size = 10) +
    scale_x_continuous(breaks = c(0, 5000000, 10000000, 15000000, 20000000, 25000000, 30000000, 35000000),
                       labels = scales::comma) +
    xlab("Base position") +
    ylab(bquote(italic(f[d]))) +
    labs(colour = "P2")

out_file = here::here(plots_dir, "20210317_abba_sliding.png")

ggsave(filename = out_file,
       device = "png",
       width = 24.75,
       height = 50,
       units = "cm",
       dpi = 300)

Karyoplot

Make custom chromosome scaffold

# Get chromosome lengths
med_chr_lens = read.table(here("data", "Oryzias_latipes.ASM223467v1.dna.toplevel.fa_chr_counts.txt"),
                          col.names = c("chr", "end"))
# Add start
med_chr_lens$start = 1
# Reorder
med_chr_lens = med_chr_lens %>% 
  dplyr::select(chr, start, end)
# Create custom genome
med_genome = regioneR::toGRanges(med_chr_lens)

Process ABBA sliding windows data

in_file = here::here("data", "introgression", "abba_sliding_final", "50000_100.txt")
# Read in data
df = readr::read_csv(in_file) %>% 
  dplyr::arrange(p1, p2, scaffold, start)

# Convert fd to 0 if D < 0
df$fd = ifelse(df$D < 0,
               0,
               df$fd)

# Change names
df = df %>% 
  dplyr::mutate(p2 = recode(df$p2, hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))

# Get df with mean of melastigma/javanicus
df_kp = df %>% 
  pivot_wider(id_cols = c(scaffold, start, end, mid, p2), names_from = p1, values_from = fd) %>%
  # get mean of melastigma/javanicus
  dplyr::mutate(mean_fd = rowMeans(dplyr::select(., melastigma, javanicus), na.rm = T)) %>% 
  dplyr::arrange(p2, scaffold, start)

knitr::kable(head(df_kp))
scaffold start end mid p2 javanicus melastigma mean_fd
1 650001 700000 666130 HdrR NA 0.1231 0.12310
1 700001 750000 721651 HdrR NA 0.2357 0.23570
1 750001 800000 774678 HdrR NA 0.1636 0.16360
1 950001 1000000 974734 HdrR NA 0.2203 0.22030
1 1000001 1050000 1028780 HdrR NA 0.2935 0.29350
1 1050001 1100000 1075868 HdrR 0.4066 0.2985 0.35255

Read in SNP density data

HNI and HSOK
in_file = here::here("data/introgression/hni_hsok.txt.gz")
# Read in file on local
ol_ranges_df = read.table(in_file,
                          header = T, 
                          sep = "\t", 
                          as.is = T)

ol_ranges_df_long = ol_ranges_df %>% 
  tidyr::pivot_longer(cols = c(hni, hsok), names_to = "line", values_to = "present")

ol_ranges_list = split(ol_ranges_df_long, f = ol_ranges_df_long$line)

ol_ranges_list = lapply(ol_ranges_list, function(x){
  # remove NAs
  df = x %>% 
    tidyr::drop_na(present)
  # convert to GRanges object
  ol_ranges = GenomicRanges::makeGRangesFromDataFrame(df,
                                                      ignore.strand = T,
                                                      seqnames.field = "chr",
                                                      start.field = "pos",
                                                      end.field = "pos")
  return(ol_ranges)
})
MIKK
in_file = here::here("data/introgression/mikk.txt.gz")
# Read in file on local
mikk_ranges_df = read.table(in_file,
                            col.names = c("chr", "pos"), 
                            sep = "\t", 
                            as.is = T)

# Convert to GRanges object

mikk_ranges = GenomicRanges::makeGRangesFromDataFrame(mikk_ranges_df,
                                                      ignore.strand = T,
                                                      seqnames.field = "chr",
                                                      start.field = "pos",
                                                      end.field = "pos")

Get exon density

# Get list of exons from biomaRt

## Select dataset
olat_mart = biomaRt::useEnsembl(biomart = "ensembl", dataset = "olatipes_gene_ensembl")
## Get attributes of interest (exon ID, chr, start, end)
exons <- biomaRt::getBM(attributes = c("chromosome_name", "ensembl_gene_id", "ensembl_transcript_id", "transcript_start", "transcript_end", "transcript_length", "ensembl_exon_id", "rank", "strand", "exon_chrom_start", "exon_chrom_end", "cds_start", "cds_end"),
               mart = olat_mart)
## Convert exons to GRanges
ex_ranges = GenomicRanges::makeGRangesFromDataFrame(exons,
                                                    ignore.strand = T,
                                                    seqnames.field = "chromosome_name",
                                                    start.field = "exon_chrom_start",
                                                    end.field = "exon_chrom_end")

All chromosomes

file_out = file.path(plots_dir, "20210318_fd_with_density_all.png")
# Save
png(file=file_out,
    width=8500,
    height=13500,
    units = "px",
    res = 400)
# Plot 
kp = plotKaryotype(med_genome)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.3)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.4)
# Add fd data
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.4)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.4)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.4)
#kpAddLabels(kp, labels="HdrR",
#            r0=0.45, r1=0.6, 
#            cex = 0.4)
kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 0.6)
dev.off()
knitr::include_graphics(basename(file_out))

Chromosome 4

out_file = file.path(plots_dir, "20210318_fd_with_density_chr_4.png")
png(file=out_file,
    width=5500,
    height=1186,
    units = "px",
    res = 400)

# Plot 
kp = plotKaryotype(med_genome, chromosomes = "4", cex = 1.5)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.7)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.8)
# Add fd data
lwd = 2
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.5)
#kpAddLabels(kp, labels="HdrR",
#            r0=0.45, r1=0.6, 
#            cex = 0.4)
kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 1)
dev.off()
knitr::include_graphics(basename(out_file))

Final figure

ABBA BABA diagram

Created with Vectr and saved here: plots/introgression/20210318_abba_diagram.svg

Compile all

abba_diagram = here::here(plots_dir, "abba_diagram.png")
tree = here::here(plots_dir, "tree_oryzias_with_ancestor.png")
karyo_chr4 = here::here(plots_dir, "20210318_fd_with_density_chr_4.png")

final_abba = ggdraw() +
  draw_image(tree,
            x = 0, y = .7, width = .4, height = .35, vjust = .1, hjust = -.1, scale = 1.2) +
  draw_image(karyo_chr4,
             x = 0, y = 0, width = 1, height = 0.3, scale = 1.2) +   
  draw_plot(fstat_plot,
             x = .4, y = .3, width = .6, height = .7) +
  draw_image(abba_diagram,
          x = 0, y = .3, width = .4, height = .35, vjust = -.05, scale = 1.1) +
  draw_plot_label(label = c("A", "B", "C", "D"), size = 16,
                  x = c(0, 0, .38, 0), y = c(1, .7, 1, .3))  


final_abba

NA
NA
ggsave(here::here(plots_dir, "20210318_final_figure.png"),
       width = 35,
       height = 21.875,
       units = "cm",
       dpi = 500)

New final figure with circos

Circos

Read in data

target_file = here::here("data/introgression/abba_sliding_final_with_icab/min-sites-250.txt")

mikk_abba_final = readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode `fd` as 0 if `D` is negative
  dplyr::mutate(fd = ifelse(D < 0, 0, fd))

Sanity check with counts of sites:

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  dplyr::count(p1, p2)

── Column specification ────────────────────────────────────────────────────────────────────────────────────────
cols(
  scaffold = col_double(),
  start = col_double(),
  end = col_double(),
  mid = col_double(),
  sites = col_double(),
  sitesUsed = col_double(),
  ABBA = col_double(),
  BABA = col_double(),
  D = col_double(),
  fd = col_double(),
  fdM = col_double(),
  p1 = col_character(),
  p2 = col_character()
)

As suggested by Simon Martin here: https://github.com/simonhmartin/genomics_general#abba-baba-statistics-in-sliding-windows > fd gives meaningless values (<0 or >1) if D is negative. If there is no excess of shared derived alleles between P2 and P3 (indicated by a positive D), then the excess cannot be quantified. fd values for windows with negative D should therefore either be discarded or converted to zero, depending on your hypothesis.

How many windows have D > 0?

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode lines
  dplyr::mutate(across(c("p1", "p2"), ~factor(.x, levels = c("icab", "hdrr", "hni", "hsok"))),
                across(c("p1", "p2"), ~recode(.x, icab = "iCab", hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))) %>% 
  dplyr::group_by(p1, p2) %>% 
  dplyr::summarise(n_pos_d = length(which(D > 0))) %>% 
  ggplot() +
    geom_col(aes(p2, n_pos_d, fill = p2)) +
    facet_wrap(~p1) +
    scale_fill_manual(values = pal_abba) +
    xlab("P2") +
    ylab("Number of windows (sites) with positive D") +
    ggtitle("Choice of P1 (iCab or HdrR)") +
    theme_cowplot() +
    labs(fill = "P2")

ggsave(here::here("plots/introgression/20210429_p1_hdrr_v_icab_counts_valid_sites.png"),
       device = "png",
       width=15.69,
       height=10,
       units = "cm",
       dpi = 400)

Distributions of \(f_D\)

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode lines
  dplyr::mutate(across(c("p1", "p2"), ~factor(.x, levels = c("icab", "hdrr", "hni", "hsok"))),
                across(c("p1", "p2"), ~recode(.x, icab = "iCab", hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))) %>%
  # remove all rows where D < 0
  dplyr::filter(D > 0) %>% 
  ggplot() +
    geom_histogram(aes(fd, fill = p2), bins = 50) +
    facet_wrap(vars(p1, p2)) +
    scale_fill_manual(values = pal_abba) +
    xlab("P2") +
#    ylab("Number of windows (sites) with positive D") +
    ggtitle(expression(italic(f[d]))) +
    theme_cowplot()  

ggsave(here::here("plots/introgression/20210429_p1_hdrr_v_icab_fd_distribution.png"),
       device = "png",
       width=15.69,
       height=10,
       units = "cm",
       dpi = 400)

Get mean fd for each population

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode lines
  dplyr::mutate(across(c("p1", "p2"), ~factor(.x, levels = c("icab", "hdrr", "hni", "hsok"))),
                across(c("p1", "p2"), ~recode(.x, icab = "iCab", hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))) %>%
  # remove all rows where D < 0
  dplyr::filter(D > 0) %>% 
  dplyr::filter(p1 == "HdrR") %>% 
  dplyr::group_by(p2) %>% 
  dplyr::summarise(mean(fd))
mikk_abba_final = readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode `fd` as 0 if `D` is negative
  dplyr::mutate(fd = ifelse(D < 0, 0, fd))

# Is iCab or HdrR closer to MIKK?
mikk_abba_final %>% 
  dplyr::filter(p2 %in% c("icab", "hdrr")) %>% 
  dplyr::group_by(p1, p2) %>% 
  dplyr::summarise(length(which(fd == 0)))

# So there are fewer 0s when HdrR is P1, which suggests that iCab is more closely related to the MIKK panel. But you want a P1 that is further away so that you'll get more data points, which is why we'll likely go with HdrR. 
mikk_abba_final = readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode `fd` as 0 if `D` is negative
  dplyr::mutate(fd = ifelse(D < 0, 0, fd))
mikk_abba_final = mikk_abba_final %>% 
  # recode lines
  dplyr::mutate(p2 = factor(p2, levels = c("hdrr", "icab", "hni", "hsok")),
                p2 = recode(p2, hdrr = "HdrR", icab = "iCab", hni = "HNI", hsok = "HSOK")) %>% 
  dplyr::arrange(p2, scaffold, start) %>% 
  dplyr::select(scaffold, mid_1 = mid, mid_2 = mid, fd, p1, p2) %>% 
  dplyr::mutate(scaffold = paste("chr", scaffold, sep ="")) %>% 
  split(., f = .$p1) %>% 
  purrr::map(., function(P1) split(P1, f = P1$p2)) %>% 
  # Remove empty data frames for hdrr-hdrr and icab-icab population combinations
  purrr::map(., function(P1) P1[purrr::map_lgl(P1, function(P2) nrow(P2) != 0)])

Plot

out_plot = here::here("plots", "introgression", "20210427_introgression_circos_MIKK_ABBA_p1-hdrr.png")
target_list = mikk_abba_final[["hdrr"]]

png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 500)

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 6))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

# Print label in center
text(0, 0, "MIKK panel\nintrogression with\niCab, HNI,\nand\nHSOK")

###############
# Introgression
###############
counter = 0

purrr::map(target_list, function(P2){
  # Set counter
  counter <<- counter + 1
  
  circos.genomicTrack(P2,
      panel.fun = function(region, value, ...){
        circos.genomicLines(region,
                            value[[1]],
                            col = pal_abba[[names(target_list[counter])]],
                            area = T,
                            border = karyoploteR::darker(pal_abba[[names(target_list[counter])]],
                                                         amount = 80))
        # Add baseline
        circos.xaxis(h = "bottom",
                     labels = F,
                     major.tick = F)
      },
      track.height = 0.1,
      bg.border = NA,
      ylim = c(0, 1))
  
  # Add axis for introgression
  circos.yaxis(side = "right",
             at = c(.5, 1),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  
  # Add y-axis label for introgression
  if (counter == 2) {
  circos.text(0, 0.5,
              labels = expression(italic(f[d])),
              sector.index = "chr1",
#              facing = "clockwise",
              adj = c(3, 0.5),
              cex = 0.4*par("cex"))
  }
  
  # Add y-axis label for introgression
  circos.text(0, 0.5,
              labels = names(target_list)[counter],
              sector.index = "chr1",
              facing = "clockwise",
              adj = c(.5, 0),
              cex = 0.6*par("cex"))  
})

circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

out_plot = here::here("plots", "introgression", "20210427_introgression_circos_MIKK_ABBA_p1-icab.png")
target_list = mikk_abba_final[["icab"]]

png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 500)

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 6))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

# Print label in center
text(0, 0, "MIKK panel\nintrogression with\nHdrR, HNI,\nand\nHSOK")

###############
# Introgression
###############
counter = 0

purrr::map(target_list, function(P2){
  # Set counter
  counter <<- counter + 1
  
  circos.genomicTrack(P2,
      panel.fun = function(region, value, ...){
        circos.genomicLines(region,
                            value[[1]],
                            col = pal_abba[[names(target_list[counter])]],
                            area = T,
                            border = karyoploteR::darker(pal_abba[[names(target_list[counter])]]))
        # Add baseline
        circos.xaxis(h = "bottom",
                     labels = F,
                     major.tick = F)
      },
      track.height = 0.1,
      bg.border = NA,
      ylim = c(0, 1))
  
  # Add axis for introgression
  circos.yaxis(side = "right",
             at = c(.5, 1),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  
  # Add y-axis label for introgression
  if (counter == 2) {
  circos.text(0, 0.5,
              labels = expression(italic(f[d])),
              sector.index = "chr1",
#              facing = "clockwise",
              adj = c(3, 0.5),
              cex = 0.4*par("cex"))
  }
  
  # Add y-axis label for introgression
  circos.text(0, 0.5,
              labels = names(target_list)[counter],
              sector.index = "chr1",
              facing = "clockwise",
              adj = c(.5, 0),
              cex = 0.6*par("cex"))  
})

circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

Re-do final figure

Chr2

Read in new data

in_file = here::here("data/introgression/abba_sliding_final_no_131-1", "500000_250.txt")
# Read in data
df = readr::read_csv(in_file) %>% 
  dplyr::arrange(p1, p2, scaffold, start)

# Convert fd to 0 if D < 0
df$fd = ifelse(df$D < 0,
               0,
               df$fd)

# Change names
df = df %>% 
  dplyr::mutate(p2 = recode(df$p2, hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))

# Get df with mean of melastigma/javanicus
df_kp = df %>% 
  pivot_wider(id_cols = c(scaffold, start, end, mid, p2), names_from = p1, values_from = fd) %>%
  # get mean of melastigma/javanicus
  dplyr::mutate(mean_fd = rowMeans(dplyr::select(., melastigma, javanicus), na.rm = T)) %>% 
  dplyr::arrange(p2, scaffold, start)

knitr::kable(head(df_kp))

Plot

chr4
out_file = file.path(plots_dir, "20210409_fd_with_density_chr_4_500kb-window.png")
png(file=out_file,
    width=5500,
    height=1186,
    units = "px",
    res = 400)

# Plot 
kp = plotKaryotype(med_genome, chromosomes = "4", cex = 1.5)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.7)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.8)
# Add fd data
lwd = 2
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.5)

kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 1)
dev.off()
knitr::include_graphics(basename(out_file))
chr2
out_file = file.path(plots_dir, "20210409_fd_with_density_chr_2_500kb-window.png")
png(file=out_file,
    width=5500,
    height=1186,
    units = "px",
    res = 400)

# Plot 
kp = plotKaryotype(med_genome, chromosomes = "2", cex = 1.5)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.7)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.8)
# Add fd data
lwd = 2
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.5)

kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 1)
dev.off()
knitr::include_graphics(basename(out_file))

Use chr4

Compose final figure

abba_diagram = here::here(plots_dir, "abba_diagram.png")
tree = here::here(plots_dir, "tree_oryzias_with_ancestor.png")
karyo_chr4 = here::here(plots_dir, "20210409_fd_with_density_chr_4_500kb-window.png")
circos_abba = here::here(plots_dir, "20210409_introgression_circos_MIKK_ABBA.png")

final_abba = ggdraw() +
  draw_image(tree,
            x = 0, y = .7, width = .4, height = .35, vjust = .1, hjust = -.1, scale = 1.2) +
  draw_image(karyo_chr4,
             x = 0, y = 0, width = 1, height = 0.3, scale = 1.2) +  
  draw_image(circos_abba,
             x = .4, y = .3, width = .6, height = .7, scale = 1.15, vjust = .025) +
  draw_image(abba_diagram,
          x = 0, y = .3, width = .4, height = .35, vjust = -.05, scale = 1.1) +
  draw_plot_label(label = c("A", "B", "C", "D"), size = 25,
                  x = c(0, 0, .45, 0), y = c(1, .7, 1, .3), color = "#4f0943")  


final_abba
ggsave(here::here(plots_dir, "20210409_introgression_final_figure.png"),
       width = 35,
       height = 21.875,
       units = "cm",
       dpi = 500)
LS0tCnRpdGxlOiAiSW50cm9ncmVzc2lvbiIKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpKWAnCiNvdXRwdXQ6CiMgIGh0bWxfZG9jdW1lbnQ6CiMgICAgdG9jOiB0cnVlCiMgICAgdG9jX2Zsb2F0OiB0cnVlCiMgICAgZGV2OiAnc3ZnJwojICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQojICAgIHBhbmRvY19hcmdzOiAtLWx1YS1maWx0ZXI9Y29sb3ItdGV4dC5sdWEKIyAgICBoaWdobGlnaHQ6IHB5Z21lbnRzICAKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKV2Ugd2FudCB0byBkZXRlcm1pbmUgdGhlIGV4dGVudCB0byB3aGljaCB0aGUgTUlLSyBwYW5lbCBzaG93cyBldmlkZW5jZSBvZiBpbnRyb2dyZXNzaW9uIHdpdGggb3RoZXIgbWVkYWthIHBvcHVsYXRpb25zLCBzcGVjaWZpY2FsbHkgdGhlIGFsbG9wYXRyaWMgTm9ydGhlcm4gYW5kIEtvcmVhbiBtZWRha2Egc3RyYWlucywgcmVsYXRpdmUgdG8gc3ltcGF0cmljIFNvdXRoZXJuIG1lZGFrYSBzdHJhaW5zLgoKIyBTZXR1cAoKYGBge3IsIG1lc3NhZ2UgPSBGfQpsaWJyYXJ5KGhlcmUpCnNvdXJjZShoZXJlOjpoZXJlKCJjb2RlIiwgInNjcmlwdHMiLCAiaW50cm9ncmVzc2lvbiIsICJzb3VyY2UuUiIpKQpgYGAKCiMjIFdvcmtpbmcgZGlyZWN0b3J5CgpXb3JraW5nIGRpcmVjdG9yeSBvbiBFQkkgY2x1c3RlcjogYC9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9pYW4vbWlra19wYXBlcmAKCiMjIENyZWF0ZSBTaW5ndWxhcml0eSBjb250YWluZXJzCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CmNvbnRhaW5lcl9kaXI9Li4vc2luZ19jb250cwojIGxvYWQgU2luZ3VsYXJpdHkgKHZlcnNpb24gMy41LjApCm1vZHVsZSBsb2FkIHNpbmd1bGFyaXR5IAoKZm9yIHBhY2thZ2UgaW4gJCggZWNobyByLWJhc2VfNC4wLjQgYmNmdG9vbHNfMS45IG51bXB5XzEuMTUuNCBiYXNoXzMuMC4yMiBiaW9jb25kdWN0b3JfMy4xMiApIDsgZG8KICBpZiBbWyAhIC1mICRjb250YWluZXJfZGlyLyRwYWNrYWdlLnNpZiBdXTsgdGhlbgogICAgc2luZ3VsYXJpdHkgYnVpbGQgXAogICAgICAtLXJlbW90ZSBcCiAgICAgICRjb250YWluZXJfZGlyLyRwYWNrYWdlLnNpZiBcCiAgICAgIGVudnMvJHBhY2thZ2UuZGVmIAogIGZpIDsKZG9uZQpgYGAKCiMjIGByZW52YAoKSW5zdGFsbCBhbGwgcmVxdWlyZWQgcGFja2FnZXMgKHVzaW5nIHItYmFzZSBpbiBTaW5ndWxhcml0eSBjb250YWluZXIpLgoKYGBge2Jhc2gsIGV2YWwgPSBGfQpjb250YWluZXJfZGlyPS4uL3NpbmdfY29udHMKYmFzZVI9ci1iYXNlXzQuMC40Cgpic3ViIC1JcyAic2luZ3VsYXJpdHkgc2hlbGwgJGNvbnRhaW5lcl9kaXIvJGJhc2VSIgpgYGAKCmBgYHtyLCBldmFsID0gRn0KIyBJbnN0YWxsIGFsbCByZXF1aXJlZCBwYWNrYWdlcwpyZW52OjpyZXN0b3JlKCkKYGBgCgojIyBDb3B5IHNjcmlwdHMgZnJvbSBTaW1vbiBNYXJ0aW4ncyBHaXRIdWIgcmVwbyAKCmBgYHtiYXNoLCBldmFsID0gRn0Kd2dldCAtUCBjb2RlL3NjcmlwdHMvaW50cm9ncmVzc2lvbiBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc2ltb25obWFydGluL2dlbm9taWNzX2dlbmVyYWwvbWFzdGVyL0FCQkFCQUJBd2luZG93cy5weQoKd2dldCAtUCBjb2RlL3NjcmlwdHMvaW50cm9ncmVzc2lvbiBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc2ltb25obWFydGluL2dlbm9taWNzX2dlbmVyYWwvbWFzdGVyL2dlbm9taWNzLnB5CmBgYAoKIyBQcm9jZXNzIG11bHRpcGxlIGFsaWdubWVudCBkYXRhIAoKIyMgRG93bmxvYWQgZnJvbSBFbnNlbWJsCgoqIFtFbnNlbWJsIDEwM117Y29sb3I9InB1cnBsZSJ9OiBPbmx5IGluY2x1ZGVzIE9yeXppYXMgbGF0aXBlcyBIZHJSIGFuZCBPcnl6aWFzIG1lbGFzdGlnbWEgKEluZGlhbiBtZWRha2EpLgoqIFtFbnNlbWJsIDEwMl17Y29sb3I9InB1cnBsZX06IEluY2x1ZGVzIGFsbCB0YXJnZXQgc3BlY2llcy4gVXNlLiAKCmBmdHA6Ly9mdHAuZW5zZW1ibC5vcmcvcHViL3JlbGVhc2UtMTAyL2VtZi9lbnNlbWJsLWNvbXBhcmEvbXVsdGlwbGVfYWxpZ25tZW50cy81MF9maXNoLmVwby9SRUFETUUuNTBfZmlzaC5lcG9gIHJlYWRzOgoKPkFsaWdubWVudHMgYXJlIGdyb3VwZWQgYnkgamFwYW5lc2UgbWVkYWthIGhkcnIgY2hyb21vc29tZSwgYW5kIHRoZW4gYnkgY29vcmRpbmF0ZSBzeXN0ZW0uCkFsaWdubWVudHMgY29udGFpbmluZyBkdXBsaWNhdGlvbnMgaW4gamFwYW5lc2UgbWVkYWthIGhkcnIgYXJlIGR1bXBlZCBvbmNlIHBlciBkdXBsaWNhdGVkIHNlZ21lbnQuClRoZSBmaWxlcyBuYW1lZCAqLm90aGVyKi5lbWYgY29udGFpbiBhbGlnbm1lbnRzIHRoYXQgZG8gbm90IGluY2x1ZGUgYW55IGphcGFuZXNlIG1lZGFrYSBoZHJyCnJlZ2lvbi4gRWFjaCBmaWxlIGNvbnRhaW5zIHVwIHRvIDIwMCBhbGlnbm1lbnRzLgoKCmBgYHtiYXNoLCBldmFsID0gRn0KZnRwX2Rpcj1mdHA6Ly9mdHAuZW5zZW1ibC5vcmcvcHViL3JlbGVhc2UtMTAyL2VtZi9lbnNlbWJsLWNvbXBhcmEvbXVsdGlwbGVfYWxpZ25tZW50cy81MF9maXNoLmVwby8KdGFyZ2V0X2Rpcj0uLi9pbnRyb2dyZXNzaW9uL3JlbGVhc2UtMTAyCgpta2RpciAtcCAkdGFyZ2V0X2Rpci9yYXcKCiMgZG93bmxvYWQsIGV4bGN1ZGluZyAqLm90aGVyKiBmaWxlcwp3Z2V0IC1QICR0YXJnZXRfZGlyL3JhdyAkZnRwX2Rpci8qIC1SICIqb3RoZXIqIgoKIyB1bnppcCBpbnRvIG5ldyBkaXJlY3RvcnkgKGV4Y2x1ZGluZyAib3RoZXIiKQokdGFyZ2V0X2Rpci91bnppcHBlZApta2RpciAtcCAkdGFyZ2V0X2Rpci91bnppcHBlZAoKZm9yIGkgaW4gJChmaW5kICR0YXJnZXRfZGlyL3Jhdy81MF9maXNoLmVwby5bMC05XSopOyBkbwogIG5hbWU9JChiYXNlbmFtZSAkaSB8IGN1dCAtZjMsNCAtZCcuJyk7CiAgYnN1YiAiemNhdCAkaSA+ICR0YXJnZXRfZGlyL3VuemlwcGVkLyRuYW1lIjsKZG9uZQpgYGAKCgoqIFsqKk5PVEUqKl17Y29sb3I9InJlZCJ9OiBGaWxlIDZfMi5lbWYgaXMgaW4gYSBjb21wbGV0ZWx5IGRpZmZlcmVudCBmb3JtYXQsIHdpdGggQ0lHQVIgc3RyaW5ncyBpbnN0ZWFkIG9mIHRoZSBub3JtYWwgU0VRLCBUUkVFLCBJRCBhbmQgREFUQSBzZWdtZW50cy4gSXQgYXBwZWFycyB0aGUgZmlsZSBpcyBjb3JydXB0ZWQuIAoqIFRoZSA2XzIgZmlsZSBpbiBgcmVsZWFzZSAxMDFgIGlzIHVuYWZmZWN0ZWQuIFJlbW92ZSBhbGwgYHJlbGVhc2UgMTAyYCBjaHIgNiBmaWxlcyBhbmQgcmVwbGFjZSB3aXRoIGByZWxlYXNlIDEwMWAgZmlsZXMuCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CiMgcmVtb3ZlIHJlbGVhc2UgMTAyIGZpbGVzIGZvciBjaHIgNgpybSAkdGFyZ2V0X2Rpci91bnppcHBlZC82XyoKCiMgZG93bmxvYWQgY2hyIDYgZmlsZXMgZnJvbSByZWxlYXNlIDEwMQpmdHBfZGlyXzEwMT1mdHA6Ly9mdHAuZW5zZW1ibC5vcmcvcHViL3JlbGVhc2UtMTAxL2VtZi9lbnNlbWJsLWNvbXBhcmEvbXVsdGlwbGVfYWxpZ25tZW50cy81MF9maXNoLmVwby8KdGFyZ2V0X2Rpcl8xMDE9Li4vaW50cm9ncmVzc2lvbi9yZWxlYXNlLTEwMQoKbWtkaXIgLXAgJHRhcmdldF9kaXJfMTAxL3JhdwoKd2dldCAtUCAkdGFyZ2V0X2Rpcl8xMDEvcmF3ICRmdHBfZGlyXzEwMS81MF9maXNoLmVwby42XyoKCiMgdW56aXAKbWtkaXIgLXAgJHRhcmdldF9kaXJfMTAxL3VuemlwcGVkCgpmb3IgaSBpbiAkKGZpbmQgJHRhcmdldF9kaXJfMTAxL3Jhdy8qKTsgZG8KICBuYW1lPSQoYmFzZW5hbWUgJGkgfCBjdXQgLWYzLDQgLWQnLicpIDsKICB6Y2F0ICRpID4gJHRhcmdldF9kaXJfMTAxL3VuemlwcGVkLyRuYW1lIDsKZG9uZQoKIyBjb3B5IG92ZXIgdG8gcmVsZWFzZSAxMDIgZGlyZWN0b3J5CmNwICR0YXJnZXRfZGlyXzEwMS91bnppcHBlZC8qICR0YXJnZXRfZGlyL3VuemlwcGVkCgpgYGAKCiMjIEdlbmVyYXRlIHRyZWUgcGxvdAoKQ29weSB0cmVlIHRvIGZpbGUKCmBgYHtiYXNoLCBldmFsID0gRn0KdHJlZV9maWxlPWRhdGEvaW50cm9ncmVzc2lvbi9yZWxlYXNlXzEwMl90cmVlLnR4dAoKYXdrICJOUj09NTgsTlI9PTIwNSIgJHRhcmdldF9kaXIvcmF3L1JFQURNRS41MF9maXNoLmVwbyBcCiAgPiAkdHJlZV9maWxlCmBgYAoKVGhlbiBtYW51YWxseSBlZGl0IGAkdHJlZV9maWxlYCB1c2luZyByZWdleCB0byBmaW5kIHNwYWNlcyBhbmQgcmVwbGFjZSB0aGVtIHdpdGggIl8iOgpge2Jhc2h9ICg/PD1bYS16XSkoICkoPz1bYS16XSlgCgpgYGB7cn0KcGh5bG9fdHJlZSA8LSBhcGU6OnJlYWQudHJlZShmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJpbnRyb2dyZXNzaW9uIiwgInJlbGVhc2VfMTAyX3RyZWUudHh0IikpCmBgYAoKIyMjIEZ1bGwgdHJlZSAKCmBgYHtyLCBmaWcud2lkdGg9MTEsIGZpZy5oZWlnaHQ9MTIuNX0KIyBDb2xvdXIgYWxsIE9yeXppYXMKaWRzIDwtIHBoeWxvX3RyZWUkdGlwLmxhYmVsW2dyZXAoIk9yeXppYXMiLCBwaHlsb190cmVlJHRpcC5sYWJlbCldCiMgZ2V0IGluZGljZXMgb2YgZWRnZXMgZGVzY2VuZGluZyBmcm9tIE1SQ0EgKGRldGVybWluZWQgdGhyb3VnaCB0cmlhbCBhbmQgZXJyb3IpCm9yeXppYXNfbm9kZXMgPC0gc2VxKDM1LCA0MikKYWxsX21lZF9jb2wgPC0gaWZlbHNlKDE6bGVuZ3RoKHBoeWxvX3RyZWVbWyJlZGdlLmxlbmd0aCJdXSkgJWluJSBvcnl6aWFzX25vZGVzLCAiI0U4NDE0MSIsICJibGFjayIpCiMgc2V0IGNvbG91cnMgZm9yIHRpcCBsYWJlbHMKYWxsX21lZF90aXAgPC0gaWZlbHNlKHBoeWxvX3RyZWUkdGlwLmxhYmVsICVpbiUgaWRzLCAiI0U4NDE0MSIsICJibGFjayIpCiMgcGxvdAphcGU6OnBsb3QucGh5bG8ocGh5bG9fdHJlZSwKICAgICAgICAgICAgICAgIHVzZS5lZGdlLmxlbmd0aCA9IFQsCiAgICAgICAgICAgICAgICBlZGdlLmNvbG9yID0gYWxsX21lZF9jb2wsCiAgICAgICAgICAgICAgICB0aXAuY29sb3IgPSBhbGxfbWVkX3RpcCwKICAgICAgICAgICAgICAgIGZvbnQgPSA0KQpgYGAKCmBgYHtyLCBldmFsID0gRn0KIyBTYXZlIHRvIHJlcG8KcG5nKGZpbGU9IGZpbGUucGF0aChwbG90c19kaXIsICJ0cmVlX2FsbC5wbmciKSwKICAgIHdpZHRoPTIyLAogICAgaGVpZ2h0PTI1LAogICAgdW5pdHMgPSAiY20iLAogICAgcmVzID0gNDAwKQphcGU6OnBsb3QucGh5bG8ocGh5bG9fdHJlZSwKICAgICAgICAgICAgICAgIHVzZS5lZGdlLmxlbmd0aCA9IFQsCiAgICAgICAgICAgICAgICBlZGdlLmNvbG9yID0gYWxsX21lZF9jb2wsCiAgICAgICAgICAgICAgICB0aXAuY29sb3IgPSBhbGxfbWVkX3RpcCwKICAgICAgICAgICAgICAgIGZvbnQgPSA0KQpkZXYub2ZmKCkKYGBgCgojIyMgT3J5emlhcyBvbmx5CgpOZXcgdHJlZSBmaWxlIGNyZWF0ZWQgbWFudWFsbHkgdG8gZXh0cmFjdCAqT3J5emlhcyogZmlzaGVzIG9ubHksIGFuZCByZXBsYWNlIHJlZmVyZW5jZSBjb2RlcyAoZS5nLiAiQVNNMjIzNDY3djEiKSB3aXRoIGxpbmUgbmFtZXMgKGUuZy4gIkhkclIiKS4KCmBgYHtyfQppbl9maWxlID0gaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL3JlbGVhc2VfMTAyX3RyZWVfb3J5emlhc19vbmx5LnR4dCIpCiMgUmVhZCBpbgpwaHlsb190cmVlIDwtIGFwZTo6cmVhZC50cmVlKGZpbGUgPSBpbl9maWxlKQojIFNldCBjb2xvdXJzIApwaHlsb19jb2xzIDwtIGMoIiM1NWI2YjAiLCAiI2YzM2E1NiIsICIjZjNiNjFmIiwgIiNmNjY3M2EiLCAiIzYzMWU2OCIpCiMgUGxvdAphcGU6OnBsb3QucGh5bG8ocGh5bG9fdHJlZSwKICAgICAgICAgICAgICAgIGZvbnQgPSA0LAogICAgICAgICAgICAgICAgdGlwLmNvbG9yID0gcGh5bG9fY29scykKCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpvdXRfZmlsZSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAidHJlZV9vcnl6aWFzLnBuZyIpCiMgU2F2ZQpwbmcoZmlsZT1vdXRfZmlsZSwKICAgIHdpZHRoPTI3MDAsCiAgICBoZWlnaHQ9MTcyMCwKICAgIHVuaXRzID0gInB4IiwKICAgIHJlcyA9IDQwMCkKYXBlOjpwbG90LnBoeWxvKHBoeWxvX3RyZWUsCiAgICAgICAgICAgICAgICBmb250ID0gNCwKICAgICAgICAgICAgICAgIHRpcC5jb2xvciA9IHBoeWxvX2NvbHMpCmRldi5vZmYoKQpgYGAKCiMjIyMgQWRkIGNyb3NzIGZvciBhbmNlc3RvcgoKYGBge3J9Cm91dF9maWxlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJ0cmVlX29yeXppYXNfd2l0aF9hbmNlc3Rvci5wbmciKQpgYGAKCmBgYHtyLCBldmFsID0gRn0KaW5fZmlsZSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAidHJlZV9vcnl6aWFzLnBuZyIpCgp0cmVlX3BhdGggPSBpbl9maWxlCgpnZ2RyYXcoKSArCiAgZHJhd19pbWFnZSh0cmVlX3BhdGgpICsKICBkcmF3X2xhYmVsKCJ4IiwKICAgICAgICAgICAgIHggPSAwLjE1MiwKICAgICAgICAgICAgIHkgPSAwLjUyLAogICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICBjb2xvciA9ICIjZjc3Y2I1IiwKICAgICAgICAgICAgIHNpemUgPSAyNSkKCmdnc2F2ZShvdXRfZmlsZSwKICAgIHdpZHRoPTE1LjY5LAogICAgaGVpZ2h0PTEwLAogICAgdW5pdHMgPSAiY20iLAogICAgZHBpID0gNDAwKQpgYGAKCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfZmlsZSkpCgppZiAoZmlsZS5leGlzdHMobmV3X3BhdGgpICE9IFQpewogIGZpbGUuY29weShvdXRfZmlsZSwgbmV3X3BhdGgpCn0KYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoYmFzZW5hbWUob3V0X2ZpbGUpKQpgYGAKCiMjIERpdmlkZSBieSBzZWdtZW50CgpgYGB7YmFzaCwgZXZhbCA9IEZ9CnRhcmdldF9kaXI9Li4vaW50cm9ncmVzc2lvbi9yZWxlYXNlLTEwMgpzZWdtZW50c19kaXI9JHRhcmdldF9kaXIvc2VnbWVudGVkCmRhdGU9MjAyMTAzMTIKc2NyaXB0PWNvZGUvc2NyaXB0cy9pbnRyb2dyZXNzaW9uLzIwMjAwOTA3X2V4dHJhY3QtZW1mLXNlZ21lbnRzLnNoCgpta2RpciAtcCAkc2VnbWVudHNfZGlyCgpmb3IgaSBpbiAkKGZpbmQgJHRhcmdldF9kaXIvdW56aXBwZWQvKiApOyBkbwogICMgZ2V0IGJhc2VuYW1lCiAgYm5hbWU9JChiYXNlbmFtZSAkaSk7CiAgYm5hbWVfc2hvcnQ9JChlY2hvICR7Ym5hbWU6Oi00fSApOwogICMgZ2V0IGNocm9tb3NvbWUKICBjaHI9JChlY2hvICRibmFtZSB8IGN1dCAtZjEgLWQiXyIgKTsKICAjIG1ha2UgZGlyZWN0b3J5IGZvciBlYWNoIEVNRiBmaWxlCiAgbmV3X3BhdGg9JChlY2hvICRzZWdtZW50c19kaXIvJGJuYW1lX3Nob3J0ICk7CiAgaWYgWyAhIC1kICIkbmV3X3BhdGgiIF07IHRoZW4KICAgIG1rZGlyICRuZXdfcGF0aDsKICBmaQogICMgZ2V0IHNlZ21lbnQgY291bnQKICBzZWdtZW50X2NvdW50PSQoZ3JlcCAiXkRBVEEiICRpIHwgd2MgLWwgKTsKICAjIGdldCBzZWdtZW50IHN0YXJ0IGFuZCBlbmQgZm9yIGVhY2ggZmlsZQogIGZvciBqIGluICQoc2VxIDEgJHNlZ21lbnRfY291bnQgKTsgZG8KICAgIGJzdWIgXAogICAgICAtbyAuLi9sb2cvJGRhdGVcc2VnbWVudF8kYm5hbWVfc2hvcnRcXyRqLm91dCBcCiAgICAgIC1lIC4uL2xvZy8kZGF0ZVxzZWdtZW50XyRibmFtZV9zaG9ydFxfJGouZXJyIFwKICAgICAgIiRzY3JpcHQgJGkgJGogJG5ld19wYXRoICIKICBkb25lOyAgCmRvbmUKCiMgSG93IG1hbnkgZmlsZXM/CmZpbmQgJHNlZ21lbnRzX2Rpci8qLyouZGF0YS50eHQgfCB3YyAtbAojIDg5NTEKZmluZCAkaW5fZGlyLyovKl8xLmRhdGEudHh0IHwgd2MgLWwKIyA0MzQxCmZpbmQgJGluX2Rpci8qLypfLTEuZGF0YS50eHQgfCB3YyAtbAojIDQ2MTAKYGBgCgojIyBSdW4gYW5hbHlzaXMgcGlwZWxpbmUgd2l0aCBgc25ha2VtYWtlYAoKYGBge2Jhc2gsIGV2YWwgPSBGfQpzbm1rX3Byb2o9ImludHJvZ3Jlc3Npb24iCgptb2R1bGUgbG9hZCBzaW5ndWxhcml0eQpjb25kYSBhY3RpdmF0ZSBzbmFrZW1ha2UKCnNuYWtlbWFrZSBcCiAtLWpvYnMgNTAwMCBcCiAtLWxhdGVuY3ktd2FpdCAxMDAgXAogLS1jbHVzdGVyLWNvbmZpZyBjb2RlL3NuYWtlbWFrZS8kc25ta19wcm9qL2NvbmZpZy9jbHVzdGVyLmpzb24gXAogLS1jbHVzdGVyICdic3ViIC1nIC9zbmFrZW1ha2VfYmdlbmllIC1KIHtjbHVzdGVyLm5hbWV9IC1uIHtjbHVzdGVyLm59IC1NIHtjbHVzdGVyLm1lbW9yeX0gLW8ge2NsdXN0ZXIub3V0cHV0fSAtZSB7Y2x1c3Rlci5lcnJvcn0nIFwKIC0ta2VlcC1nb2luZyBcCiAtLXJlcnVuLWluY29tcGxldGUgXAogLS11c2UtY29uZGEgXAogLS11c2Utc2luZ3VsYXJpdHkgXAogLXMgY29kZS9zbmFrZW1ha2UvJHNubWtfcHJvai9TbmFrZWZpbGUgXAogLXAKYGBgCgojICpmKiBzdGF0aXN0aWMgYW5hbHlzaXMKCiMjIFJlYWQgaW4gZGF0YQoKYGBge3IsIHJlc3VsdHMgPSAnYXNpcyd9CmRhdGFfZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAiaW50cm9ncmVzc2lvbiIsICIyMDIxMDMxNV9mX3N0YXRfZmluYWwudHh0IikKIyBSZWFkIGluIGRhdGEKZmluYWxfZGYgPC0gcmVhZC50YWJsZShkYXRhX2ZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICAgIGFzLmlzID0gVCkKCmZpbmFsX2RmIDwtIGZpbmFsX2RmICU+JSAKICBkcGx5cjo6bXV0YXRlKGFjcm9zcyhQMiwKICAgICAgICAgICAgICAgICAgICAgICB+ZmFjdG9yKC54LCBsZXZlbHMgPSBmaXNoX29yZGVyKSkpICU+JSAKICBkcGx5cjo6bXV0YXRlKGNociA9IGZhY3RvcihjaHIsIGxldmVscyA9IGNocl9vcmRlcikpCgprbml0cjo6a2FibGUoaGVhZChmaW5hbF9kZikpCmBgYAoKCiMjIENyZWF0ZSBERiB3aXRoIG1lYW4gYG1lbGFzdGlnbWFgIGFuZCBgamF2YW5pY3VzYAoKYGBge3IsIHJlc3VsdHMgPSAnYXNpcyd9CmNvcl9kZiA8LSBmaW5hbF9kZiAlPiUgCiAgIyBmaWx0ZXIgZm9yIHdoZW4gUDEgaXMgYW5vdGhlciBPcnl6aWFzLCBhbmQgUDIgCiAgZHBseXI6OmZpbHRlcihQMSAlaW4lIGMoImphdmFuaWN1cyIsICJtZWxhc3RpZ21hIikgJiBQMiAhPSAiTUlLSyIgJiBQMyA9PSAiTUlLSyIpICU+JSAKICAjIHBpdm90IHRvIHB1dCB0aGUgYWRtaXh0dXJlX2Ygc3RhdCBmb3IgbWVsYXN0aWdtYSBhbmQgamF2YW5pY3VzIGluIHRoZSBzYW1lIHJvdwogIHRpZHlyOjpwaXZvdF93aWRlcihpZF9jb2xzID0gYygiUDIiLCAiY2hyIiksCiAgICAgICAgICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBQMSwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBjKGFkbWl4X2YsIGZfY2lfbG93ZXIsIGZfY2lfdXBwZXIpKQoKY29yX2RmJGNociA8LSBhcy5jaGFyYWN0ZXIoY29yX2RmJGNocikKY29yX2RmJGNociA8LSBpZmVsc2UoY29yX2RmJGNociA9PSAiYWxsIiwgImdlbm9tZS13aWRlIiwgY29yX2RmJGNocikKY2hyX29yZGVyX3Bsb3QgPC0gYyhzZXEoMSwyNCksICJnZW5vbWUtd2lkZSIpCmNvcl9kZiRjaHIgPC0gZmFjdG9yKGNvcl9kZiRjaHIsIGxldmVscyA9IGNocl9vcmRlcl9wbG90KQoKY29yX2RmX21lYW5zIDwtIGNvcl9kZiAlPiUKICAjIGFwcGx5IGFjcm9zcyByb3dzCiAgZHBseXI6OnJvd3dpc2UoKSAlPiUgCiAgIyBnZXQgbWVhbnMgZm9yIGYgYW5kIENJcwogIGRwbHlyOjptdXRhdGUobWVhbl9mID0gbWVhbihjKGFkbWl4X2ZfamF2YW5pY3VzLCBhZG1peF9mX21lbGFzdGlnbWEpKSwKICAgICAgICAgICAgICAgIG1lYW5fY2lfdXBwZXIgPSBtZWFuKGMoZl9jaV91cHBlcl9qYXZhbmljdXMsIGZfY2lfdXBwZXJfbWVsYXN0aWdtYSkpLAogICAgICAgICAgICAgICAgbWVhbl9jaV9sb3dlciA9IG1lYW4oYyhmX2NpX2xvd2VyX2phdmFuaWN1cywgZl9jaV9sb3dlcl9tZWxhc3RpZ21hKSkpICU+JSAKICAjIHNldCBzdGF0cyBhdCBhIG1heGltdW0gb2YgMQogIGRwbHlyOjptdXRhdGUoYWNyb3NzKGMoIm1lYW5fZiIsICJtZWFuX2NpX3VwcGVyIiwgIm1lYW5fY2lfbG93ZXIiKSwKICAgICAgICAgICAgICAgICAgICAgICB+ZHBseXI6OmlmX2Vsc2UoLnggPiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAueCkpKQoKa25pdHI6OmthYmxlKGhlYWQoY29yX2RmX21lYW5zKSkKYGBgCgojIyBQbG90CgpgYGB7cn0KZnN0YXRfcGxvdCA9IGNvcl9kZl9tZWFucyAlPiUgCiAgZ2dwbG90KGFlcyhQMiwgbWVhbl9mLCBmaWxsID0gUDIpKSArCiAgICBnZW9tX2NvbCgpICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBtZWFuX2NpX2xvd2VyLAogICAgICAgICAgICAgICAgICAgICAgeW1heCA9IG1lYW5fY2lfdXBwZXIpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSksCiAgICAgICAgICAgICAgICAgIHdpZHRoID0gMC4yNSkgKyAgCiAgICBndWlkZXMoZmlsbCA9IEYpICsKICAgIGZhY2V0X3dyYXAofmNocikgKwogICAgeWxpbSgwLDEpICsKICAgIHlsYWIoZXhwcmVzc2lvbihwYXN0ZSgiTWVhbiAiLCBpdGFsaWMoImYiKSwgIiBzdGF0aXN0aWMiKSkpICsKICAgIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFsX2FiYmEpCgpmc3RhdF9wbG90CmBgYAoKYGBge3IsIGV2YWwgPSBGfQpvdXRfZmlsZSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiMjAyMTAzMTVfZl9zdGF0IikKCiMgUE5HCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKG91dF9maWxlLCAiLnBuZyIsIHNlcCA9ICIiKSwKICAgICAgIGRldmljZSA9ICJwbmciLAogICAgICAgd2lkdGggPSAyNC43NSwKICAgICAgIGhlaWdodCA9IDE5LjUsCiAgICAgICB1bml0cyA9ICJjbSIsCiAgICAgICBkcGkgPSA1MDApCgojIFNWRwpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZShvdXRfZmlsZSwgIi5zdmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAic3ZnIiwKICAgICAgIHdpZHRoID0gMjQuNzUsCiAgICAgICBoZWlnaHQgPSAxOS41LAogICAgICAgdW5pdHMgPSAiY20iKQpgYGAKCiMgU2xpZGluZyB3aW5kb3dzIEFCQkEgQkFCQQoKIyMgUmVhZCBpbiBkYXRhCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CmluX2ZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgImludHJvZ3Jlc3Npb24iLCAiYWJiYV9zbGlkaW5nX2ZpbmFsIiwgIjUwMDAwXzEwMC50eHQiKQojIFJlYWQgaW4gZGF0YQpkZiA9IHJlYWRyOjpyZWFkX2Nzdihpbl9maWxlKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UocDEsIHAyLCBzY2FmZm9sZCwgc3RhcnQpCgojIENvbnZlcnQgZmQgdG8gMCBpZiBEIDwgMApkZiRmZCA9IGlmZWxzZShkZiREIDwgMCwKICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgZGYkZmQpCgojIENoYW5nZSBuYW1lcwpkZiA9IGRmICU+JSAKICBkcGx5cjo6bXV0YXRlKHAyID0gcmVjb2RlKGRmJHAyLCBoZHJyID0gIkhkclIiLCBobmkgPSAiSE5JIiwgaHNvayA9ICJIU09LIikpCgoKYGBgCgojIyBQbG90CgojIyMgU3RhbmRhcmQKCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDIwfQpkZiAlPiUgCiAgZHBseXI6OmZpbHRlcihwMSA9PSAibWVsYXN0aWdtYSIpICU+JSAKICBnZ3Bsb3QoKSArCiAgICBnZW9tX2xpbmUoYWVzKG1pZCwgZmQsIGNvbG91ciA9IHAyKSkgKwogICAgZmFjZXRfd3JhcCh+c2NhZmZvbGQsIG5yb3cgPSAyNCwgbmNvbCA9IDEpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gcGFsX2FiYmEpICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLCA1MDAwMDAwLCAxMDAwMDAwMCwgMTUwMDAwMDAsIDIwMDAwMDAwLCAyNTAwMDAwMCwgMzAwMDAwMDAsIDM1MDAwMDAwKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArCiAgICB4bGFiKCJCYXNlIHBvc2l0aW9uIikgKwogICAgeWxhYihicXVvdGUoaXRhbGljKGZbZF0pKSkgKwogICAgbGFicyhjb2xvdXIgPSAiUDIiKQpgYGAKCmBgYHtyLCBldmFsID0gRn0Kb3V0X2ZpbGUgPSBoZXJlOjpoZXJlKHBsb3RzX2RpciwgIjIwMjEwMzE3X2FiYmFfc2xpZGluZy5wbmciKQoKZ2dzYXZlKGZpbGVuYW1lID0gb3V0X2ZpbGUsCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHdpZHRoID0gMjQuNzUsCiAgICAgICBoZWlnaHQgPSA1MCwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDMwMCkKYGBgCgojIyMgS2FyeW9wbG90CgojIyMjIE1ha2UgY3VzdG9tIGNocm9tb3NvbWUgc2NhZmZvbGQKCmBgYHtyfQojIEdldCBjaHJvbW9zb21lIGxlbmd0aHMKbWVkX2Nocl9sZW5zID0gcmVhZC50YWJsZShoZXJlKCJkYXRhIiwgIk9yeXppYXNfbGF0aXBlcy5BU00yMjM0Njd2MS5kbmEudG9wbGV2ZWwuZmFfY2hyX2NvdW50cy50eHQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJjaHIiLCAiZW5kIikpCiMgQWRkIHN0YXJ0Cm1lZF9jaHJfbGVucyRzdGFydCA9IDEKIyBSZW9yZGVyCm1lZF9jaHJfbGVucyA9IG1lZF9jaHJfbGVucyAlPiUgCiAgZHBseXI6OnNlbGVjdChjaHIsIHN0YXJ0LCBlbmQpCiMgQ3JlYXRlIGN1c3RvbSBnZW5vbWUKbWVkX2dlbm9tZSA9IHJlZ2lvbmVSOjp0b0dSYW5nZXMobWVkX2Nocl9sZW5zKQpgYGAKCiMjIyMgIFByb2Nlc3MgQUJCQSBzbGlkaW5nIHdpbmRvd3MgZGF0YQoKYGBge3IsIG1lc3NhZ2UgPSBGLCByZXN1bHRzID0gJ2FzaXMnfQppbl9maWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJpbnRyb2dyZXNzaW9uIiwgImFiYmFfc2xpZGluZ19maW5hbCIsICI1MDAwMF8xMDAudHh0IikKIyBSZWFkIGluIGRhdGEKZGYgPSByZWFkcjo6cmVhZF9jc3YoaW5fZmlsZSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKHAxLCBwMiwgc2NhZmZvbGQsIHN0YXJ0KQoKIyBDb252ZXJ0IGZkIHRvIDAgaWYgRCA8IDAKZGYkZmQgPSBpZmVsc2UoZGYkRCA8IDAsCiAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgIGRmJGZkKQoKIyBDaGFuZ2UgbmFtZXMKZGYgPSBkZiAlPiUgCiAgZHBseXI6Om11dGF0ZShwMiA9IHJlY29kZShkZiRwMiwgaGRyciA9ICJIZHJSIiwgaG5pID0gIkhOSSIsIGhzb2sgPSAiSFNPSyIpKQoKIyBHZXQgZGYgd2l0aCBtZWFuIG9mIG1lbGFzdGlnbWEvamF2YW5pY3VzCmRmX2twID0gZGYgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBjKHNjYWZmb2xkLCBzdGFydCwgZW5kLCBtaWQsIHAyKSwgbmFtZXNfZnJvbSA9IHAxLCB2YWx1ZXNfZnJvbSA9IGZkKSAlPiUKICAjIGdldCBtZWFuIG9mIG1lbGFzdGlnbWEvamF2YW5pY3VzCiAgZHBseXI6Om11dGF0ZShtZWFuX2ZkID0gcm93TWVhbnMoZHBseXI6OnNlbGVjdCguLCBtZWxhc3RpZ21hLCBqYXZhbmljdXMpLCBuYS5ybSA9IFQpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UocDIsIHNjYWZmb2xkLCBzdGFydCkKCmtuaXRyOjprYWJsZShoZWFkKGRmX2twKSkKYGBgCgojIyMjIFJlYWQgaW4gU05QIGRlbnNpdHkgZGF0YQoKIyMjIyMgSE5JIGFuZCBIU09LCgpgYGB7ciwgZXZhbCA9IEZ9CmluX2ZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL2ludHJvZ3Jlc3Npb24vaG5pX2hzb2sudHh0Lmd6IikKIyBSZWFkIGluIGZpbGUgb24gbG9jYWwKb2xfcmFuZ2VzX2RmID0gcmVhZC50YWJsZShpbl9maWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmlzID0gVCkKCm9sX3Jhbmdlc19kZl9sb25nID0gb2xfcmFuZ2VzX2RmICU+JSAKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGhuaSwgaHNvayksIG5hbWVzX3RvID0gImxpbmUiLCB2YWx1ZXNfdG8gPSAicHJlc2VudCIpCgpvbF9yYW5nZXNfbGlzdCA9IHNwbGl0KG9sX3Jhbmdlc19kZl9sb25nLCBmID0gb2xfcmFuZ2VzX2RmX2xvbmckbGluZSkKCm9sX3Jhbmdlc19saXN0ID0gbGFwcGx5KG9sX3Jhbmdlc19saXN0LCBmdW5jdGlvbih4KXsKICAjIHJlbW92ZSBOQXMKICBkZiA9IHggJT4lIAogICAgdGlkeXI6OmRyb3BfbmEocHJlc2VudCkKICAjIGNvbnZlcnQgdG8gR1JhbmdlcyBvYmplY3QKICBvbF9yYW5nZXMgPSBHZW5vbWljUmFuZ2VzOjptYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5zdHJhbmQgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXFuYW1lcy5maWVsZCA9ICJjaHIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydC5maWVsZCA9ICJwb3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQuZmllbGQgPSAicG9zIikKICByZXR1cm4ob2xfcmFuZ2VzKQp9KQoKYGBgCgpgYGB7ciwgZXZhbCA9IEYsIGluY2x1ZGUgPSBGfQojIFNhdmUgdG8gc3BlZWQgdXAgd2hlbiByZW5kZXJpbmcgSFRNTApzYXZlUkRTKG9sX3Jhbmdlc19saXN0LCBoZXJlOjpoZXJlKCJkYXRhL2ludHJvZ3Jlc3Npb24vaG5pX2hzb2tfcmFuZ2UucmRzIikpCmBgYAoKYGBge3IsIGluY2x1ZGUgPSBGfQpvbF9yYW5nZXNfbGlzdCA9IHJlYWRSRFMoaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL2huaV9oc29rX3JhbmdlLnJkcyIpKQpgYGAKCiMjIyMjIE1JS0sKCmBgYHtyLCBldmFsID0gRn0KaW5fZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9taWtrLnR4dC5neiIpCiMgUmVhZCBpbiBmaWxlIG9uIGxvY2FsCm1pa2tfcmFuZ2VzX2RmID0gcmVhZC50YWJsZShpbl9maWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gYygiY2hyIiwgInBvcyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuaXMgPSBUKQoKIyBDb252ZXJ0IHRvIEdSYW5nZXMgb2JqZWN0CgptaWtrX3JhbmdlcyA9IEdlbm9taWNSYW5nZXM6Om1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShtaWtrX3Jhbmdlc19kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLnN0cmFuZCA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gImNociIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0LmZpZWxkID0gInBvcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJwb3MiKQpgYGAKCmBgYHtyLCBldmFsID0gRiwgaW5jbHVkZSA9IEZ9CiMgU2F2ZSB0byBzcGVlZCB1cCB3aGVuIHJlbmRlcmluZyBIVE1MCnNhdmVSRFMobWlra19yYW5nZXMsIGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9taWtrX3JhbmdlLnJkcyIpKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KbWlra19yYW5nZXMgPSByZWFkUkRTKGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9taWtrX3JhbmdlLnJkcyIpKQpgYGAKCiMjIyMgR2V0IGV4b24gZGVuc2l0eQoKYGBge3IsIGV2YWwgPSBGfQojIEdldCBsaXN0IG9mIGV4b25zIGZyb20gYmlvbWFSdAoKIyMgU2VsZWN0IGRhdGFzZXQKb2xhdF9tYXJ0ID0gYmlvbWFSdDo6dXNlRW5zZW1ibChiaW9tYXJ0ID0gImVuc2VtYmwiLCBkYXRhc2V0ID0gIm9sYXRpcGVzX2dlbmVfZW5zZW1ibCIpCiMjIEdldCBhdHRyaWJ1dGVzIG9mIGludGVyZXN0IChleG9uIElELCBjaHIsIHN0YXJ0LCBlbmQpCmV4b25zIDwtIGJpb21hUnQ6OmdldEJNKGF0dHJpYnV0ZXMgPSBjKCJjaHJvbW9zb21lX25hbWUiLCAiZW5zZW1ibF9nZW5lX2lkIiwgImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsICJ0cmFuc2NyaXB0X3N0YXJ0IiwgInRyYW5zY3JpcHRfZW5kIiwgInRyYW5zY3JpcHRfbGVuZ3RoIiwgImVuc2VtYmxfZXhvbl9pZCIsICJyYW5rIiwgInN0cmFuZCIsICJleG9uX2Nocm9tX3N0YXJ0IiwgImV4b25fY2hyb21fZW5kIiwgImNkc19zdGFydCIsICJjZHNfZW5kIiksCiAgICAgICAgICAgICAgIG1hcnQgPSBvbGF0X21hcnQpCiMjIENvbnZlcnQgZXhvbnMgdG8gR1JhbmdlcwpleF9yYW5nZXMgPSBHZW5vbWljUmFuZ2VzOjptYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZXhvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmUuc3RyYW5kID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gImNocm9tb3NvbWVfbmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydC5maWVsZCA9ICJleG9uX2Nocm9tX3N0YXJ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJleG9uX2Nocm9tX2VuZCIpCmBgYAoKYGBge3IsIGV2YWwgPSBGLCBpbmNsdWRlID0gRn0KIyBTYXZlIHRvIHNwZWVkIHVwIHdoZW4gcmVuZGVyaW5nIEhUTUwKc2F2ZVJEUyhleF9yYW5nZXMsIGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9leF9yYW5nZS5yZHMiKSkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CmV4X3JhbmdlcyA9IHJlYWRSRFMoaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL2V4X3JhbmdlLnJkcyIpKQpgYGAKCiMjIyMgQWxsIGNocm9tb3NvbWVzCgpgYGB7cn0KZmlsZV9vdXQgPSBmaWxlLnBhdGgocGxvdHNfZGlyLCAiMjAyMTAzMThfZmRfd2l0aF9kZW5zaXR5X2FsbC5wbmciKQpgYGAKCgpgYGB7ciwgZXZhbCA9IEZ9CiMgU2F2ZQpwbmcoZmlsZT1maWxlX291dCwKICAgIHdpZHRoPTg1MDAsCiAgICBoZWlnaHQ9MTM1MDAsCiAgICB1bml0cyA9ICJweCIsCiAgICByZXMgPSA0MDApCiMgUGxvdCAKa3AgPSBwbG90S2FyeW90eXBlKG1lZF9nZW5vbWUpCiMgQWRkIGJhc2UgbnVtYmVycyAKa2FyeW9wbG90ZVI6OmtwQWRkQmFzZU51bWJlcnMoa3AsIHRpY2suZGlzdCA9IDUwMDAwMDAsIGNleCA9IDAuMykKIyBBZGQgZGF0YSBiYWNrZ3JvdW5kcwprYXJ5b3Bsb3RlUjo6a3BEYXRhQmFja2dyb3VuZChrcCwgcjA9MCwgcjEgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpCiMgQWRkIGF4aXMgbGFiZWwKa3BBeGlzKGtwLCByMD0wLjMsIHIxID0gMSwgY2V4ID0gMC40KQojIEFkZCBmZCBkYXRhCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIHggPSBkZl9rcCRtaWRbZGZfa3AkcDIgPT0gIkhOSSJdLAogICAgICAgICAgICAgICAgICAgICB5ID0gZGZfa3AkbWVhbl9mZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjRjY2NzNBIiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEpCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjRjNCNjFGIiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEpCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSFNPSyJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjNjMxRTY4IiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEpCiMgQWRkIFNOUCBkZW5zaXR5IGRhdGEKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1taWtrX3JhbmdlcywgY29sID0gIiM0OUEzNzkiLAogICAgICAgICAgICAgIHIwPTAsIHIxPTAuMSwgCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1vbF9yYW5nZXNfbGlzdCRobmksIGNvbCA9ICIjRjY2NzNBIiwKICAgICAgICAgICAgICByMD0wLjEsIHIxPTAuMiwgCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1vbF9yYW5nZXNfbGlzdCRoc29rLCBjb2wgPSAiIzYzMUU2OCIsIAogICAgICAgICAgICAgIHIwPTAuMiwgcjE9MC4zLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQoja3BQbG90RGVuc2l0eShrcCwgZGF0YT1vbF9yYW5nZXNfbGlzdCRoZHJyLCBjb2wgPSAiI0YzQjYxRiIsCiMgICAgICAgICAgICAgIHIwPTAuNDUsIHIxPTAuNiwKIyAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKIyBBZGQgZXhvbiBkZW5zaXR5IHRvIGlkZW9ncmFtCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9ZXhfcmFuZ2VzLCBjb2wgPSAiI2Y3N2NiNSIsCiAgICAgICAgICAgICAgZGF0YS5wYW5lbCA9ICJpZGVvZ3JhbSIsCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCwKICAgICAgICAgICAgICByMCA9IDAuNSwgcjEgPSAxKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPWV4X3JhbmdlcywgY29sID0gIiNmNzdjYjUiLAogICAgICAgICAgICAgIGRhdGEucGFuZWwgPSAiaWRlb2dyYW0iLAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDAsCiAgICAgICAgICAgICAgcjAgPSAwLjUsIHIxID0gMCkKIyBBZGQgbGFiZWxzCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9Ik1JS0siLAogICAgICAgICAgICByMD0wLCByMT0wLjA1LAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAwMSwKICAgICAgICAgICAgY2V4ID0gMC40KQprcEFkZExhYmVscyhrcCwgbGFiZWxzPSJITkkiLAogICAgICAgICAgICByMD0wLjEsIHIxPTAuMTUsIAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAwMSwKICAgICAgICAgICAgY2V4ID0gMC40KQprcEFkZExhYmVscyhrcCwgbGFiZWxzPSJIU09LIiwKICAgICAgICAgICAgcjA9MC4yLCByMT0wLjI1LAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAwMSwKICAgICAgICAgICAgY2V4ID0gMC40KQoja3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iSGRyUiIsCiMgICAgICAgICAgICByMD0wLjQ1LCByMT0wLjYsIAojICAgICAgICAgICAgY2V4ID0gMC40KQprcEFkZExhYmVscyhrcCwgbGFiZWxzPWJxdW90ZShpdGFsaWMoZltkXSkpLAogICAgICAgICAgICByMD0wLjMsIHIxPTEsIAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAzNSwKICAgICAgICAgICAgY2V4ID0gMC42KQpkZXYub2ZmKCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShmaWxlX291dCkpCgppZiAoZmlsZS5leGlzdHMobmV3X3BhdGgpICE9IFQpewogIGZpbGUuY29weShmaWxlX291dCwgbmV3X3BhdGgpCn0KYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoYmFzZW5hbWUoZmlsZV9vdXQpKQpgYGAKCiMjIyMgQ2hyb21vc29tZSA0CgpgYGB7cn0Kb3V0X2ZpbGUgPSBmaWxlLnBhdGgocGxvdHNfZGlyLCAiMjAyMTAzMThfZmRfd2l0aF9kZW5zaXR5X2Nocl80LnBuZyIpCmBgYAoKCmBgYHtyLCBldmFsID0gRn0KcG5nKGZpbGU9b3V0X2ZpbGUsCiAgICB3aWR0aD01NTAwLAogICAgaGVpZ2h0PTExODYsCiAgICB1bml0cyA9ICJweCIsCiAgICByZXMgPSA0MDApCgojIFBsb3QgCmtwID0gcGxvdEthcnlvdHlwZShtZWRfZ2Vub21lLCBjaHJvbW9zb21lcyA9ICI0IiwgY2V4ID0gMS41KQojIEFkZCBiYXNlIG51bWJlcnMgCmthcnlvcGxvdGVSOjprcEFkZEJhc2VOdW1iZXJzKGtwLCB0aWNrLmRpc3QgPSA1MDAwMDAwLCBjZXggPSAwLjcpCiMgQWRkIGRhdGEgYmFja2dyb3VuZHMKa2FyeW9wbG90ZVI6OmtwRGF0YUJhY2tncm91bmQoa3AsIHIwPTAsIHIxID0gMSwgY29sb3IgPSAid2hpdGUiKQojIEFkZCBheGlzIGxhYmVsCmtwQXhpcyhrcCwgcjA9MC4zLCByMSA9IDEsIGNleCA9IDAuOCkKIyBBZGQgZmQgZGF0YQpsd2QgPSAyCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIHggPSBkZl9rcCRtaWRbZGZfa3AkcDIgPT0gIkhOSSJdLAogICAgICAgICAgICAgICAgICAgICB5ID0gZGZfa3AkbWVhbl9mZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjRjY2NzNBIiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEsCiAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IGx3ZCkKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIHggPSBkZl9rcCRtaWRbZGZfa3AkcDIgPT0gIkhkclIiXSwKICAgICAgICAgICAgICAgICAgICAgeSA9IGRmX2twJG1lYW5fZmRbZGZfa3AkcDIgPT0gIkhkclIiXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiNGM0I2MUYiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSwKICAgICAgICAgICAgICAgICAgICAgbHdkID0gbHdkKQprYXJ5b3Bsb3RlUjo6a3BMaW5lcyhrcCwKICAgICAgICAgICAgICAgICAgICAgY2hyID0gZGZfa3Akc2NhZmZvbGRbZGZfa3AkcDIgPT0gIkhTT0siXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSFNPSyJdLAogICAgICAgICAgICAgICAgICAgICB5ID0gZGZfa3AkbWVhbl9mZFtkZl9rcCRwMiA9PSAiSFNPSyJdLAogICAgICAgICAgICAgICAgICAgICBjb2wgPSAiIzYzMUU2OCIsCiAgICAgICAgICAgICAgICAgICAgIHIwPTAuMywgcjEgPSAxLAogICAgICAgICAgICAgICAgICAgICBsd2QgPSBsd2QpCiMgQWRkIFNOUCBkZW5zaXR5IGRhdGEKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1taWtrX3JhbmdlcywgY29sID0gIiM0OUEzNzkiLAogICAgICAgICAgICAgIHIwPTAsIHIxPTAuMSwgCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1vbF9yYW5nZXNfbGlzdCRobmksIGNvbCA9ICIjRjY2NzNBIiwKICAgICAgICAgICAgICByMD0wLjEsIHIxPTAuMiwgCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1vbF9yYW5nZXNfbGlzdCRoc29rLCBjb2wgPSAiIzYzMUU2OCIsIAogICAgICAgICAgICAgIHIwPTAuMiwgcjE9MC4zLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQoja3BQbG90RGVuc2l0eShrcCwgZGF0YT1vbF9yYW5nZXNfbGlzdCRoZHJyLCBjb2wgPSAiI0YzQjYxRiIsCiMgICAgICAgICAgICAgIHIwPTAuNDUsIHIxPTAuNiwKIyAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKIyBBZGQgZXhvbiBkZW5zaXR5IHRvIGlkZW9ncmFtCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9ZXhfcmFuZ2VzLCBjb2wgPSAiI2Y3N2NiNSIsCiAgICAgICAgICAgICAgZGF0YS5wYW5lbCA9ICJpZGVvZ3JhbSIsCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCwKICAgICAgICAgICAgICByMCA9IDAuNSwgcjEgPSAxKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPWV4X3JhbmdlcywgY29sID0gIiNmNzdjYjUiLAogICAgICAgICAgICAgIGRhdGEucGFuZWwgPSAiaWRlb2dyYW0iLAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDAsCiAgICAgICAgICAgICAgcjAgPSAwLjUsIHIxID0gMCkKIyBBZGQgbGFiZWxzCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9Ik1JS0siLAogICAgICAgICAgICByMD0wLCByMT0wLjA1LAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAwMSwKICAgICAgICAgICAgY2V4ID0gMC41KQprcEFkZExhYmVscyhrcCwgbGFiZWxzPSJITkkiLAogICAgICAgICAgICByMD0wLjEsIHIxPTAuMTUsIAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAwMSwKICAgICAgICAgICAgY2V4ID0gMC41KQprcEFkZExhYmVscyhrcCwgbGFiZWxzPSJIU09LIiwKICAgICAgICAgICAgcjA9MC4yLCByMT0wLjI1LAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAwMSwKICAgICAgICAgICAgY2V4ID0gMC41KQoja3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iSGRyUiIsCiMgICAgICAgICAgICByMD0wLjQ1LCByMT0wLjYsIAojICAgICAgICAgICAgY2V4ID0gMC40KQprcEFkZExhYmVscyhrcCwgbGFiZWxzPWJxdW90ZShpdGFsaWMoZltkXSkpLAogICAgICAgICAgICByMD0wLjMsIHIxPTEsIAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAzNSwKICAgICAgICAgICAgY2V4ID0gMSkKZGV2Lm9mZigpCmBgYAoKYGBge3IsIGluY2x1ZGUgPSBGfQojIGNvcHkgdG8gc2FtZSBkaXJlY3RvcnkgYXMgY3VycmVudCBub3RlYm9vawpjdXJyZW50X2RpciA9IGRpcm5hbWUocnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGgpCgpuZXdfcGF0aCA9IGZpbGUucGF0aChjdXJyZW50X2RpciwgYmFzZW5hbWUob3V0X2ZpbGUpKQoKaWYgKGZpbGUuZXhpc3RzKG5ld19wYXRoKSAhPSBUKXsKICBmaWxlLmNvcHkob3V0X2ZpbGUsIG5ld19wYXRoKQp9CmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGJhc2VuYW1lKG91dF9maWxlKSkKYGBgCgojIEZpbmFsIGZpZ3VyZQoKIyMgQUJCQSBCQUJBIGRpYWdyYW0KCkNyZWF0ZWQgd2l0aCBbVmVjdHJdKGh0dHBzOi8vdmVjdHIuY29tLykgYW5kIHNhdmVkIGhlcmU6IGBwbG90cy9pbnRyb2dyZXNzaW9uLzIwMjEwMzE4X2FiYmFfZGlhZ3JhbS5zdmdgCgojIyBDb21waWxlIGFsbAoKYGBge3IsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD04Ljh9CmFiYmFfZGlhZ3JhbSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiYWJiYV9kaWFncmFtLnBuZyIpCnRyZWUgPSBoZXJlOjpoZXJlKHBsb3RzX2RpciwgInRyZWVfb3J5emlhc193aXRoX2FuY2VzdG9yLnBuZyIpCmthcnlvX2NocjQgPSBoZXJlOjpoZXJlKHBsb3RzX2RpciwgIjIwMjEwMzE4X2ZkX3dpdGhfZGVuc2l0eV9jaHJfNC5wbmciKQoKZmluYWxfYWJiYSA9IGdnZHJhdygpICsKICBkcmF3X2ltYWdlKHRyZWUsCiAgICAgICAgICAgIHggPSAwLCB5ID0gLjcsIHdpZHRoID0gLjQsIGhlaWdodCA9IC4zNSwgdmp1c3QgPSAuMSwgaGp1c3QgPSAtLjEsIHNjYWxlID0gMS4yKSArCiAgZHJhd19pbWFnZShrYXJ5b19jaHI0LAogICAgICAgICAgICAgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IDEsIGhlaWdodCA9IDAuMywgc2NhbGUgPSAxLjIpICsgICAKICBkcmF3X3Bsb3QoZnN0YXRfcGxvdCwKICAgICAgICAgICAgIHggPSAuNCwgeSA9IC4zLCB3aWR0aCA9IC42LCBoZWlnaHQgPSAuNykgKwogIGRyYXdfaW1hZ2UoYWJiYV9kaWFncmFtLAogICAgICAgICAgeCA9IDAsIHkgPSAuMywgd2lkdGggPSAuNCwgaGVpZ2h0ID0gLjM1LCB2anVzdCA9IC0uMDUsIHNjYWxlID0gMS4xKSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiQSIsICJCIiwgIkMiLCAiRCIpLCBzaXplID0gMTYsCiAgICAgICAgICAgICAgICAgIHggPSBjKDAsIDAsIC4zOCwgMCksIHkgPSBjKDEsIC43LCAxLCAuMykpICAKCgpmaW5hbF9hYmJhCgoKYGBgCmBgYHtyLCBldmFsID0gRn0KZ2dzYXZlKGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiMjAyMTAzMThfZmluYWxfZmlndXJlLnBuZyIpLAogICAgICAgd2lkdGggPSAzNSwKICAgICAgIGhlaWdodCA9IDIxLjg3NSwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgojIE5ldyBmaW5hbCBmaWd1cmUgd2l0aCBjaXJjb3MKCiMjIENpcmNvcwoKIyMjIFJlYWQgaW4gZGF0YQoKYGBge3IsIG1lc3NhZ2UgPSBGfQp0YXJnZXRfZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9hYmJhX3NsaWRpbmdfZmluYWxfd2l0aF9pY2FiL21pbi1zaXRlcy0yNTAudHh0IikKYGBgCgpTYW5pdHkgY2hlY2sgd2l0aCBjb3VudHMgb2Ygc2l0ZXM6CgpgYGB7cn0KcmVhZHI6OnJlYWRfY3N2KHRhcmdldF9maWxlKSAlPiUgCiAgIyBhZGQgc2xpZGluZyB3aW5kb3cgbGVuZ3RoCiAgZHBseXI6Om11dGF0ZSh3aW5kb3dfbGVuZ3RoX2tiID0gKGVuZCAtIHN0YXJ0ICsgMSkgLyAxMDAwKSAlPiUgCiAgIyBmaWx0ZXIgZm9yIDUwMCBrYiB3aW5kb3dzCiAgZHBseXI6OmZpbHRlcih3aW5kb3dfbGVuZ3RoX2tiID09IDUwMCkgJT4lIAogIGRwbHlyOjpjb3VudChwMSwgcDIpCmBgYAoKCkFzIHN1Z2dlc3RlZCBieSBTaW1vbiBNYXJ0aW4gaGVyZTogPGh0dHBzOi8vZ2l0aHViLmNvbS9zaW1vbmhtYXJ0aW4vZ2Vub21pY3NfZ2VuZXJhbCNhYmJhLWJhYmEtc3RhdGlzdGljcy1pbi1zbGlkaW5nLXdpbmRvd3M+Cj4gZmQgZ2l2ZXMgbWVhbmluZ2xlc3MgdmFsdWVzICg8MCBvciA+MSkgaWYgRCBpcyBuZWdhdGl2ZS4gSWYgdGhlcmUgaXMgbm8gZXhjZXNzIG9mIHNoYXJlZCBkZXJpdmVkIGFsbGVsZXMgYmV0d2VlbiBQMiBhbmQgUDMgKGluZGljYXRlZCBieSBhIHBvc2l0aXZlIEQpLCB0aGVuIHRoZSBleGNlc3MgY2Fubm90IGJlIHF1YW50aWZpZWQuIGZkIHZhbHVlcyBmb3Igd2luZG93cyB3aXRoIG5lZ2F0aXZlIEQgc2hvdWxkIHRoZXJlZm9yZSBlaXRoZXIgYmUgZGlzY2FyZGVkIG9yIGNvbnZlcnRlZCB0byB6ZXJvLCBkZXBlbmRpbmcgb24geW91ciBoeXBvdGhlc2lzLgoKIyMjIyBIb3cgbWFueSB3aW5kb3dzIGhhdmUgRCA+IDA/IAoKYGBge3IsIG1lc3NhZ2UgPSBGfQpyZWFkcjo6cmVhZF9jc3YodGFyZ2V0X2ZpbGUpICU+JSAKICAjIGFkZCBzbGlkaW5nIHdpbmRvdyBsZW5ndGgKICBkcGx5cjo6bXV0YXRlKHdpbmRvd19sZW5ndGhfa2IgPSAoZW5kIC0gc3RhcnQgKyAxKSAvIDEwMDApICU+JSAKICAjIGZpbHRlciBmb3IgNTAwIGtiIHdpbmRvd3MKICBkcGx5cjo6ZmlsdGVyKHdpbmRvd19sZW5ndGhfa2IgPT0gNTAwKSAlPiUgCiAgIyByZWNvZGUgbGluZXMKICBkcGx5cjo6bXV0YXRlKGFjcm9zcyhjKCJwMSIsICJwMiIpLCB+ZmFjdG9yKC54LCBsZXZlbHMgPSBjKCJpY2FiIiwgImhkcnIiLCAiaG5pIiwgImhzb2siKSkpLAogICAgICAgICAgICAgICAgYWNyb3NzKGMoInAxIiwgInAyIiksIH5yZWNvZGUoLngsIGljYWIgPSAiaUNhYiIsIGhkcnIgPSAiSGRyUiIsIGhuaSA9ICJITkkiLCBoc29rID0gIkhTT0siKSkpICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkocDEsIHAyKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShuX3Bvc19kID0gbGVuZ3RoKHdoaWNoKEQgPiAwKSkpICU+JSAKICBnZ3Bsb3QoKSArCiAgICBnZW9tX2NvbChhZXMocDIsIG5fcG9zX2QsIGZpbGwgPSBwMikpICsKICAgIGZhY2V0X3dyYXAofnAxKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxfYWJiYSkgKwogICAgeGxhYigiUDIiKSArCiAgICB5bGFiKCJOdW1iZXIgb2Ygd2luZG93cyAoc2l0ZXMpIHdpdGggcG9zaXRpdmUgRCIpICsKICAgIGdndGl0bGUoIkNob2ljZSBvZiBQMSAoaUNhYiBvciBIZHJSKSIpICsKICAgIHRoZW1lX2Nvd3Bsb3QoKSArCiAgICBsYWJzKGZpbGwgPSAiUDIiKQpgYGAKCmBgYHtyLCBldmFsID0gRn0KZ2dzYXZlKGhlcmU6OmhlcmUoInBsb3RzL2ludHJvZ3Jlc3Npb24vMjAyMTA0MjlfcDFfaGRycl92X2ljYWJfY291bnRzX3ZhbGlkX3NpdGVzLnBuZyIpLAogICAgICAgZGV2aWNlID0gInBuZyIsCiAgICAgICB3aWR0aD0xNS42OSwKICAgICAgIGhlaWdodD0xMCwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDQwMCkKYGBgCgojIyMjIERpc3RyaWJ1dGlvbnMgb2YgJGZfRCQKCmBgYHtyLCBtZXNzYWdlID0gRn0KcmVhZHI6OnJlYWRfY3N2KHRhcmdldF9maWxlKSAlPiUgCiAgIyBhZGQgc2xpZGluZyB3aW5kb3cgbGVuZ3RoCiAgZHBseXI6Om11dGF0ZSh3aW5kb3dfbGVuZ3RoX2tiID0gKGVuZCAtIHN0YXJ0ICsgMSkgLyAxMDAwKSAlPiUgCiAgIyBmaWx0ZXIgZm9yIDUwMCBrYiB3aW5kb3dzCiAgZHBseXI6OmZpbHRlcih3aW5kb3dfbGVuZ3RoX2tiID09IDUwMCkgJT4lIAogICMgcmVjb2RlIGxpbmVzCiAgZHBseXI6Om11dGF0ZShhY3Jvc3MoYygicDEiLCAicDIiKSwgfmZhY3RvcigueCwgbGV2ZWxzID0gYygiaWNhYiIsICJoZHJyIiwgImhuaSIsICJoc29rIikpKSwKICAgICAgICAgICAgICAgIGFjcm9zcyhjKCJwMSIsICJwMiIpLCB+cmVjb2RlKC54LCBpY2FiID0gImlDYWIiLCBoZHJyID0gIkhkclIiLCBobmkgPSAiSE5JIiwgaHNvayA9ICJIU09LIikpKSAlPiUKICAjIHJlbW92ZSBhbGwgcm93cyB3aGVyZSBEIDwgMAogIGRwbHlyOjpmaWx0ZXIoRCA+IDApICU+JSAKICBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoZmQsIGZpbGwgPSBwMiksIGJpbnMgPSA1MCkgKwogICAgZmFjZXRfd3JhcCh2YXJzKHAxLCBwMikpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbF9hYmJhKSArCiAgICB4bGFiKCJQMiIpICsKIyAgICB5bGFiKCJOdW1iZXIgb2Ygd2luZG93cyAoc2l0ZXMpIHdpdGggcG9zaXRpdmUgRCIpICsKICAgIGdndGl0bGUoZXhwcmVzc2lvbihpdGFsaWMoZltkXSkpKSArCiAgICB0aGVtZV9jb3dwbG90KCkgIAoKYGBgCmBgYHtyLCBldmFsID0gRn0KZ2dzYXZlKGhlcmU6OmhlcmUoInBsb3RzL2ludHJvZ3Jlc3Npb24vMjAyMTA0MjlfcDFfaGRycl92X2ljYWJfZmRfZGlzdHJpYnV0aW9uLnBuZyIpLAogICAgICAgZGV2aWNlID0gInBuZyIsCiAgICAgICB3aWR0aD0xNS42OSwKICAgICAgIGhlaWdodD0xMCwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDQwMCkKYGBgCgojIyMjIEdldCBtZWFuIGZkIGZvciBlYWNoIHBvcHVsYXRpb24KCmBgYHtyLCBtZXNzYWdlID0gRn0KcmVhZHI6OnJlYWRfY3N2KHRhcmdldF9maWxlKSAlPiUgCiAgIyBhZGQgc2xpZGluZyB3aW5kb3cgbGVuZ3RoCiAgZHBseXI6Om11dGF0ZSh3aW5kb3dfbGVuZ3RoX2tiID0gKGVuZCAtIHN0YXJ0ICsgMSkgLyAxMDAwKSAlPiUgCiAgIyBmaWx0ZXIgZm9yIDUwMCBrYiB3aW5kb3dzCiAgZHBseXI6OmZpbHRlcih3aW5kb3dfbGVuZ3RoX2tiID09IDUwMCkgJT4lIAogICMgcmVjb2RlIGxpbmVzCiAgZHBseXI6Om11dGF0ZShhY3Jvc3MoYygicDEiLCAicDIiKSwgfmZhY3RvcigueCwgbGV2ZWxzID0gYygiaWNhYiIsICJoZHJyIiwgImhuaSIsICJoc29rIikpKSwKICAgICAgICAgICAgICAgIGFjcm9zcyhjKCJwMSIsICJwMiIpLCB+cmVjb2RlKC54LCBpY2FiID0gImlDYWIiLCBoZHJyID0gIkhkclIiLCBobmkgPSAiSE5JIiwgaHNvayA9ICJIU09LIikpKSAlPiUKICAjIHJlbW92ZSBhbGwgcm93cyB3aGVyZSBEIDwgMAogIGRwbHlyOjpmaWx0ZXIoRCA+IDApICU+JSAKICBkcGx5cjo6ZmlsdGVyKHAxID09ICJIZHJSIikgJT4lIAogIGRwbHlyOjpncm91cF9ieShwMikgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UobWVhbihmZCkpCmBgYAoKCmBgYHtyLCBtZXNzYWdlID0gRn0KbWlra19hYmJhX2ZpbmFsID0gcmVhZHI6OnJlYWRfY3N2KHRhcmdldF9maWxlKSAlPiUgCiAgIyBhZGQgc2xpZGluZyB3aW5kb3cgbGVuZ3RoCiAgZHBseXI6Om11dGF0ZSh3aW5kb3dfbGVuZ3RoX2tiID0gKGVuZCAtIHN0YXJ0ICsgMSkgLyAxMDAwKSAlPiUgCiAgIyBmaWx0ZXIgZm9yIDUwMCBrYiB3aW5kb3dzCiAgZHBseXI6OmZpbHRlcih3aW5kb3dfbGVuZ3RoX2tiID09IDUwMCkgJT4lIAogICMgcmVjb2RlIGBmZGAgYXMgMCBpZiBgRGAgaXMgbmVnYXRpdmUKICBkcGx5cjo6bXV0YXRlKGZkID0gaWZlbHNlKEQgPCAwLCAwLCBmZCkpCgojIElzIGlDYWIgb3IgSGRyUiBjbG9zZXIgdG8gTUlLSz8KbWlra19hYmJhX2ZpbmFsICU+JSAKICBkcGx5cjo6ZmlsdGVyKHAyICVpbiUgYygiaWNhYiIsICJoZHJyIikpICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkocDEsIHAyKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShsZW5ndGgod2hpY2goZmQgPT0gMCkpKQoKIyBTbyB0aGVyZSBhcmUgZmV3ZXIgMHMgd2hlbiBIZHJSIGlzIFAxLCB3aGljaCBzdWdnZXN0cyB0aGF0IGlDYWIgaXMgbW9yZSBjbG9zZWx5IHJlbGF0ZWQgdG8gdGhlIE1JS0sgcGFuZWwuIEJ1dCB5b3Ugd2FudCBhIFAxIHRoYXQgaXMgZnVydGhlciBhd2F5IHNvIHRoYXQgeW91J2xsIGdldCBtb3JlIGRhdGEgcG9pbnRzLCB3aGljaCBpcyB3aHkgd2UnbGwgbGlrZWx5IGdvIHdpdGggSGRyUi4gCmBgYAoKCmBgYHtyLCBtZXNzYWdlID0gRn0KbWlra19hYmJhX2ZpbmFsID0gbWlra19hYmJhX2ZpbmFsICU+JSAKICAjIHJlY29kZSBsaW5lcwogIGRwbHlyOjptdXRhdGUocDIgPSBmYWN0b3IocDIsIGxldmVscyA9IGMoImhkcnIiLCAiaWNhYiIsICJobmkiLCAiaHNvayIpKSwKICAgICAgICAgICAgICAgIHAyID0gcmVjb2RlKHAyLCBoZHJyID0gIkhkclIiLCBpY2FiID0gImlDYWIiLCBobmkgPSAiSE5JIiwgaHNvayA9ICJIU09LIikpICU+JSAKICBkcGx5cjo6YXJyYW5nZShwMiwgc2NhZmZvbGQsIHN0YXJ0KSAlPiUgCiAgZHBseXI6OnNlbGVjdChzY2FmZm9sZCwgbWlkXzEgPSBtaWQsIG1pZF8yID0gbWlkLCBmZCwgcDEsIHAyKSAlPiUgCiAgZHBseXI6Om11dGF0ZShzY2FmZm9sZCA9IHBhc3RlKCJjaHIiLCBzY2FmZm9sZCwgc2VwID0iIikpICU+JSAKICBzcGxpdCguLCBmID0gLiRwMSkgJT4lIAogIHB1cnJyOjptYXAoLiwgZnVuY3Rpb24oUDEpIHNwbGl0KFAxLCBmID0gUDEkcDIpKSAlPiUgCiAgIyBSZW1vdmUgZW1wdHkgZGF0YSBmcmFtZXMgZm9yIGhkcnItaGRyciBhbmQgaWNhYi1pY2FiIHBvcHVsYXRpb24gY29tYmluYXRpb25zCiAgcHVycnI6Om1hcCguLCBmdW5jdGlvbihQMSkgUDFbcHVycnI6Om1hcF9sZ2woUDEsIGZ1bmN0aW9uKFAyKSBucm93KFAyKSAhPSAwKV0pCgpgYGAKCiMjIyBQbG90CgpgYGB7cn0Kb3V0X3Bsb3QgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJpbnRyb2dyZXNzaW9uIiwgIjIwMjEwNDI3X2ludHJvZ3Jlc3Npb25fY2lyY29zX01JS0tfQUJCQV9wMS1oZHJyLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQp0YXJnZXRfbGlzdCA9IG1pa2tfYWJiYV9maW5hbFtbImhkcnIiXV0KCnBuZyhvdXRfcGxvdCwKICAgIHdpZHRoID0gMjAsCiAgICBoZWlnaHQgPSAyMCwKICAgIHVuaXRzID0gImNtIiwKICAgIHJlcyA9IDUwMCkKCiMgU2V0IHBhcmFtZXRlcnMKIyMgRGVjcmVhc2UgY2VsbCBwYWRkaW5nIGZyb20gZGVmYXVsdCBjKDAuMDIsIDEuMDAsIDAuMDIsIDEuMDApCmNpcmNvcy5wYXIoY2VsbC5wYWRkaW5nID0gYygwLCAwLCAwLCAwKSwKICAgICAgICAgICB0cmFjay5tYXJnaW4gPSBjKDAsIDApLAogICAgICAgICAgIGdhcC5kZWdyZWUgPSBjKHJlcCgxLCBucm93KGNocm9tcykgLSAxKSwgNikpCiMgSW5pdGlhbGl6ZSBwbG90CmNpcmNvcy5pbml0aWFsaXplV2l0aElkZW9ncmFtKGNocm9tcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdFR5cGUgPSBjKCJheGlzIiwgImxhYmVscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvci5ieSA9IDFlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5sYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpKQoKIyBQcmludCBsYWJlbCBpbiBjZW50ZXIKdGV4dCgwLCAwLCAiTUlLSyBwYW5lbFxuaW50cm9ncmVzc2lvbiB3aXRoXG5pQ2FiLCBITkksXG5hbmRcbkhTT0siKQoKIyMjIyMjIyMjIyMjIyMjCiMgSW50cm9ncmVzc2lvbgojIyMjIyMjIyMjIyMjIyMKY291bnRlciA9IDAKCnB1cnJyOjptYXAodGFyZ2V0X2xpc3QsIGZ1bmN0aW9uKFAyKXsKICAjIFNldCBjb3VudGVyCiAgY291bnRlciA8PC0gY291bnRlciArIDEKICAKICBjaXJjb3MuZ2Vub21pY1RyYWNrKFAyLAogICAgICBwYW5lbC5mdW4gPSBmdW5jdGlvbihyZWdpb24sIHZhbHVlLCAuLi4pewogICAgICAgIGNpcmNvcy5nZW5vbWljTGluZXMocmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVbWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHBhbF9hYmJhW1tuYW1lcyh0YXJnZXRfbGlzdFtjb3VudGVyXSldXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZWEgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyID0ga2FyeW9wbG90ZVI6OmRhcmtlcihwYWxfYWJiYVtbbmFtZXModGFyZ2V0X2xpc3RbY291bnRlcl0pXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudCA9IDgwKSkKICAgICAgICAjIEFkZCBiYXNlbGluZQogICAgICAgIGNpcmNvcy54YXhpcyhoID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG1ham9yLnRpY2sgPSBGKQogICAgICB9LAogICAgICB0cmFjay5oZWlnaHQgPSAwLjEsCiAgICAgIGJnLmJvcmRlciA9IE5BLAogICAgICB5bGltID0gYygwLCAxKSkKICAKICAjIEFkZCBheGlzIGZvciBpbnRyb2dyZXNzaW9uCiAgY2lyY29zLnlheGlzKHNpZGUgPSAicmlnaHQiLAogICAgICAgICAgICAgYXQgPSBjKC41LCAxKSwKICAgICAgICAgICAgIGxhYmVscy5jZXggPSAwLjI1KnBhcigiY2V4IiksCiAgICAgICAgICAgICB0aWNrLmxlbmd0aCA9IDIKICAgICAgICAgICAgICkKICAKICAjIEFkZCB5LWF4aXMgbGFiZWwgZm9yIGludHJvZ3Jlc3Npb24KICBpZiAoY291bnRlciA9PSAyKSB7CiAgY2lyY29zLnRleHQoMCwgMC41LAogICAgICAgICAgICAgIGxhYmVscyA9IGV4cHJlc3Npb24oaXRhbGljKGZbZF0pKSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiMgICAgICAgICAgICAgIGZhY2luZyA9ICJjbG9ja3dpc2UiLAogICAgICAgICAgICAgIGFkaiA9IGMoMywgMC41KSwKICAgICAgICAgICAgICBjZXggPSAwLjQqcGFyKCJjZXgiKSkKICB9CiAgCiAgIyBBZGQgeS1heGlzIGxhYmVsIGZvciBpbnRyb2dyZXNzaW9uCiAgY2lyY29zLnRleHQoMCwgMC41LAogICAgICAgICAgICAgIGxhYmVscyA9IG5hbWVzKHRhcmdldF9saXN0KVtjb3VudGVyXSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsCiAgICAgICAgICAgICAgYWRqID0gYyguNSwgMCksCiAgICAgICAgICAgICAgY2V4ID0gMC42KnBhcigiY2V4IikpICAKfSkKCmNpcmNvcy5jbGVhcigpCgpkZXYub2ZmKCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfcGxvdCkpCgpmaWxlLmNvcHkob3V0X3Bsb3QsIG5ld19wYXRoLCBvdmVyd3JpdGUgPSBUKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfcGxvdCkpCmBgYApgYGB7cn0Kb3V0X3Bsb3QgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJpbnRyb2dyZXNzaW9uIiwgIjIwMjEwNDI3X2ludHJvZ3Jlc3Npb25fY2lyY29zX01JS0tfQUJCQV9wMS1pY2FiLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQp0YXJnZXRfbGlzdCA9IG1pa2tfYWJiYV9maW5hbFtbImljYWIiXV0KCnBuZyhvdXRfcGxvdCwKICAgIHdpZHRoID0gMjAsCiAgICBoZWlnaHQgPSAyMCwKICAgIHVuaXRzID0gImNtIiwKICAgIHJlcyA9IDUwMCkKCiMgU2V0IHBhcmFtZXRlcnMKIyMgRGVjcmVhc2UgY2VsbCBwYWRkaW5nIGZyb20gZGVmYXVsdCBjKDAuMDIsIDEuMDAsIDAuMDIsIDEuMDApCmNpcmNvcy5wYXIoY2VsbC5wYWRkaW5nID0gYygwLCAwLCAwLCAwKSwKICAgICAgICAgICB0cmFjay5tYXJnaW4gPSBjKDAsIDApLAogICAgICAgICAgIGdhcC5kZWdyZWUgPSBjKHJlcCgxLCBucm93KGNocm9tcykgLSAxKSwgNikpCiMgSW5pdGlhbGl6ZSBwbG90CmNpcmNvcy5pbml0aWFsaXplV2l0aElkZW9ncmFtKGNocm9tcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdFR5cGUgPSBjKCJheGlzIiwgImxhYmVscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvci5ieSA9IDFlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5sYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpKQoKIyBQcmludCBsYWJlbCBpbiBjZW50ZXIKdGV4dCgwLCAwLCAiTUlLSyBwYW5lbFxuaW50cm9ncmVzc2lvbiB3aXRoXG5IZHJSLCBITkksXG5hbmRcbkhTT0siKQoKIyMjIyMjIyMjIyMjIyMjCiMgSW50cm9ncmVzc2lvbgojIyMjIyMjIyMjIyMjIyMKY291bnRlciA9IDAKCnB1cnJyOjptYXAodGFyZ2V0X2xpc3QsIGZ1bmN0aW9uKFAyKXsKICAjIFNldCBjb3VudGVyCiAgY291bnRlciA8PC0gY291bnRlciArIDEKICAKICBjaXJjb3MuZ2Vub21pY1RyYWNrKFAyLAogICAgICBwYW5lbC5mdW4gPSBmdW5jdGlvbihyZWdpb24sIHZhbHVlLCAuLi4pewogICAgICAgIGNpcmNvcy5nZW5vbWljTGluZXMocmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVbWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHBhbF9hYmJhW1tuYW1lcyh0YXJnZXRfbGlzdFtjb3VudGVyXSldXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZWEgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyID0ga2FyeW9wbG90ZVI6OmRhcmtlcihwYWxfYWJiYVtbbmFtZXModGFyZ2V0X2xpc3RbY291bnRlcl0pXV0pKQogICAgICAgICMgQWRkIGJhc2VsaW5lCiAgICAgICAgY2lyY29zLnhheGlzKGggPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gRiwKICAgICAgICAgICAgICAgICAgICAgbWFqb3IudGljayA9IEYpCiAgICAgIH0sCiAgICAgIHRyYWNrLmhlaWdodCA9IDAuMSwKICAgICAgYmcuYm9yZGVyID0gTkEsCiAgICAgIHlsaW0gPSBjKDAsIDEpKQogIAogICMgQWRkIGF4aXMgZm9yIGludHJvZ3Jlc3Npb24KICBjaXJjb3MueWF4aXMoc2lkZSA9ICJyaWdodCIsCiAgICAgICAgICAgICBhdCA9IGMoLjUsIDEpLAogICAgICAgICAgICAgbGFiZWxzLmNleCA9IDAuMjUqcGFyKCJjZXgiKSwKICAgICAgICAgICAgIHRpY2subGVuZ3RoID0gMgogICAgICAgICAgICAgKQogIAogICMgQWRkIHktYXhpcyBsYWJlbCBmb3IgaW50cm9ncmVzc2lvbgogIGlmIChjb3VudGVyID09IDIpIHsKICBjaXJjb3MudGV4dCgwLCAwLjUsCiAgICAgICAgICAgICAgbGFiZWxzID0gZXhwcmVzc2lvbihpdGFsaWMoZltkXSkpLAogICAgICAgICAgICAgIHNlY3Rvci5pbmRleCA9ICJjaHIxIiwKIyAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsCiAgICAgICAgICAgICAgYWRqID0gYygzLCAwLjUpLAogICAgICAgICAgICAgIGNleCA9IDAuNCpwYXIoImNleCIpKQogIH0KICAKICAjIEFkZCB5LWF4aXMgbGFiZWwgZm9yIGludHJvZ3Jlc3Npb24KICBjaXJjb3MudGV4dCgwLCAwLjUsCiAgICAgICAgICAgICAgbGFiZWxzID0gbmFtZXModGFyZ2V0X2xpc3QpW2NvdW50ZXJdLAogICAgICAgICAgICAgIHNlY3Rvci5pbmRleCA9ICJjaHIxIiwKICAgICAgICAgICAgICBmYWNpbmcgPSAiY2xvY2t3aXNlIiwKICAgICAgICAgICAgICBhZGogPSBjKC41LCAwKSwKICAgICAgICAgICAgICBjZXggPSAwLjYqcGFyKCJjZXgiKSkgIAp9KQoKY2lyY29zLmNsZWFyKCkKCmRldi5vZmYoKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KIyBjb3B5IHRvIHNhbWUgZGlyZWN0b3J5IGFzIGN1cnJlbnQgbm90ZWJvb2sKY3VycmVudF9kaXIgPSBkaXJuYW1lKHJzdHVkaW9hcGk6OmdldFNvdXJjZUVkaXRvckNvbnRleHQoKSRwYXRoKQoKbmV3X3BhdGggPSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGJhc2VuYW1lKG91dF9wbG90KSkKCmZpbGUuY29weShvdXRfcGxvdCwgbmV3X3BhdGgsIG92ZXJ3cml0ZSA9IFQpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGJhc2VuYW1lKG91dF9wbG90KSkKYGBgCgojIyBSZS1kbyBmaW5hbCBmaWd1cmUKCiMjIyBDaHIyCgojIyMjIFJlYWQgaW4gbmV3IGRhdGEKCmBgYHtyLCBtZXNzYWdlID0gRiwgcmVzdWx0cyA9ICdhc2lzJ30KaW5fZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9hYmJhX3NsaWRpbmdfZmluYWxfbm9fMTMxLTEiLCAiNTAwMDAwXzI1MC50eHQiKQojIFJlYWQgaW4gZGF0YQpkZiA9IHJlYWRyOjpyZWFkX2Nzdihpbl9maWxlKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UocDEsIHAyLCBzY2FmZm9sZCwgc3RhcnQpCgojIENvbnZlcnQgZmQgdG8gMCBpZiBEIDwgMApkZiRmZCA9IGlmZWxzZShkZiREIDwgMCwKICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgZGYkZmQpCgojIENoYW5nZSBuYW1lcwpkZiA9IGRmICU+JSAKICBkcGx5cjo6bXV0YXRlKHAyID0gcmVjb2RlKGRmJHAyLCBoZHJyID0gIkhkclIiLCBobmkgPSAiSE5JIiwgaHNvayA9ICJIU09LIikpCgojIEdldCBkZiB3aXRoIG1lYW4gb2YgbWVsYXN0aWdtYS9qYXZhbmljdXMKZGZfa3AgPSBkZiAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoc2NhZmZvbGQsIHN0YXJ0LCBlbmQsIG1pZCwgcDIpLCBuYW1lc19mcm9tID0gcDEsIHZhbHVlc19mcm9tID0gZmQpICU+JQogICMgZ2V0IG1lYW4gb2YgbWVsYXN0aWdtYS9qYXZhbmljdXMKICBkcGx5cjo6bXV0YXRlKG1lYW5fZmQgPSByb3dNZWFucyhkcGx5cjo6c2VsZWN0KC4sIG1lbGFzdGlnbWEsIGphdmFuaWN1cyksIG5hLnJtID0gVCkpICU+JSAKICBkcGx5cjo6YXJyYW5nZShwMiwgc2NhZmZvbGQsIHN0YXJ0KQoKa25pdHI6OmthYmxlKGhlYWQoZGZfa3ApKQpgYGAKCiMjIyMgUGxvdAoKIyMjIyMgY2hyNAoKYGBge3J9Cm91dF9maWxlID0gZmlsZS5wYXRoKHBsb3RzX2RpciwgIjIwMjEwNDA5X2ZkX3dpdGhfZGVuc2l0eV9jaHJfNF81MDBrYi13aW5kb3cucG5nIikKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9CnBuZyhmaWxlPW91dF9maWxlLAogICAgd2lkdGg9NTUwMCwKICAgIGhlaWdodD0xMTg2LAogICAgdW5pdHMgPSAicHgiLAogICAgcmVzID0gNDAwKQoKIyBQbG90IAprcCA9IHBsb3RLYXJ5b3R5cGUobWVkX2dlbm9tZSwgY2hyb21vc29tZXMgPSAiNCIsIGNleCA9IDEuNSkKIyBBZGQgYmFzZSBudW1iZXJzIAprYXJ5b3Bsb3RlUjo6a3BBZGRCYXNlTnVtYmVycyhrcCwgdGljay5kaXN0ID0gNTAwMDAwMCwgY2V4ID0gMC43KQojIEFkZCBkYXRhIGJhY2tncm91bmRzCmthcnlvcGxvdGVSOjprcERhdGFCYWNrZ3JvdW5kKGtwLCByMD0wLCByMSA9IDEsIGNvbG9yID0gIndoaXRlIikKIyBBZGQgYXhpcyBsYWJlbAprcEF4aXMoa3AsIHIwPTAuMywgcjEgPSAxLCBjZXggPSAwLjgpCiMgQWRkIGZkIGRhdGEKbHdkID0gMgprYXJ5b3Bsb3RlUjo6a3BMaW5lcyhrcCwKICAgICAgICAgICAgICAgICAgICAgY2hyID0gZGZfa3Akc2NhZmZvbGRbZGZfa3AkcDIgPT0gIkhOSSJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgeSA9IGRmX2twJG1lYW5fZmRbZGZfa3AkcDIgPT0gIkhOSSJdLAogICAgICAgICAgICAgICAgICAgICBjb2wgPSAiI0Y2NjczQSIsCiAgICAgICAgICAgICAgICAgICAgIHIwPTAuMywgcjEgPSAxLAogICAgICAgICAgICAgICAgICAgICBsd2QgPSBsd2QpCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjRjNCNjFGIiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEsCiAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IGx3ZCkKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIHggPSBkZl9rcCRtaWRbZGZfa3AkcDIgPT0gIkhTT0siXSwKICAgICAgICAgICAgICAgICAgICAgeSA9IGRmX2twJG1lYW5fZmRbZGZfa3AkcDIgPT0gIkhTT0siXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiM2MzFFNjgiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSwKICAgICAgICAgICAgICAgICAgICAgbHdkID0gbHdkKQojIEFkZCBTTlAgZGVuc2l0eSBkYXRhCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9bWlra19yYW5nZXMsIGNvbCA9ICIjNDlBMzc5IiwKICAgICAgICAgICAgICByMD0wLCByMT0wLjEsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9b2xfcmFuZ2VzX2xpc3QkaG5pLCBjb2wgPSAiI0Y2NjczQSIsCiAgICAgICAgICAgICAgcjA9MC4xLCByMT0wLjIsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9b2xfcmFuZ2VzX2xpc3QkaHNvaywgY29sID0gIiM2MzFFNjgiLCAKICAgICAgICAgICAgICByMD0wLjIsIHIxPTAuMywgCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKI2twUGxvdERlbnNpdHkoa3AsIGRhdGE9b2xfcmFuZ2VzX2xpc3QkaGRyciwgY29sID0gIiNGM0I2MUYiLAojICAgICAgICAgICAgICByMD0wLjQ1LCByMT0wLjYsCiMgICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCiMgQWRkIGV4b24gZGVuc2l0eSB0byBpZGVvZ3JhbQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPWV4X3JhbmdlcywgY29sID0gIiNmNzdjYjUiLAogICAgICAgICAgICAgIGRhdGEucGFuZWwgPSAiaWRlb2dyYW0iLAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDAsCiAgICAgICAgICAgICAgcjAgPSAwLjUsIHIxID0gMSkKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1leF9yYW5nZXMsIGNvbCA9ICIjZjc3Y2I1IiwKICAgICAgICAgICAgICBkYXRhLnBhbmVsID0gImlkZW9ncmFtIiwKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwLAogICAgICAgICAgICAgIHIwID0gMC41LCByMSA9IDApCiMgQWRkIGxhYmVscwprcEFkZExhYmVscyhrcCwgbGFiZWxzPSJNSUtLIiwKICAgICAgICAgICAgcjA9MCwgcjE9MC4wNSwKICAgICAgICAgICAgbGFiZWwubWFyZ2luID0gMC4wMDEsCiAgICAgICAgICAgIGNleCA9IDAuNSkKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iSE5JIiwKICAgICAgICAgICAgcjA9MC4xLCByMT0wLjE1LCAKICAgICAgICAgICAgbGFiZWwubWFyZ2luID0gMC4wMDEsCiAgICAgICAgICAgIGNleCA9IDAuNSkKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iSFNPSyIsCiAgICAgICAgICAgIHIwPTAuMiwgcjE9MC4yNSwKICAgICAgICAgICAgbGFiZWwubWFyZ2luID0gMC4wMDEsCiAgICAgICAgICAgIGNleCA9IDAuNSkKCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9YnF1b3RlKGl0YWxpYyhmW2RdKSksCiAgICAgICAgICAgIHIwPTAuMywgcjE9MSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDM1LAogICAgICAgICAgICBjZXggPSAxKQpkZXYub2ZmKCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfZmlsZSkpCgpmaWxlLmNvcHkob3V0X2ZpbGUsIG5ld19wYXRoLCBvdmVyd3JpdGUgPSBUKQoKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoYmFzZW5hbWUob3V0X2ZpbGUpKQpgYGAKIyMjIyMgY2hyMgoKYGBge3J9Cm91dF9maWxlID0gZmlsZS5wYXRoKHBsb3RzX2RpciwgIjIwMjEwNDA5X2ZkX3dpdGhfZGVuc2l0eV9jaHJfMl81MDBrYi13aW5kb3cucG5nIikKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9CnBuZyhmaWxlPW91dF9maWxlLAogICAgd2lkdGg9NTUwMCwKICAgIGhlaWdodD0xMTg2LAogICAgdW5pdHMgPSAicHgiLAogICAgcmVzID0gNDAwKQoKIyBQbG90IAprcCA9IHBsb3RLYXJ5b3R5cGUobWVkX2dlbm9tZSwgY2hyb21vc29tZXMgPSAiMiIsIGNleCA9IDEuNSkKIyBBZGQgYmFzZSBudW1iZXJzIAprYXJ5b3Bsb3RlUjo6a3BBZGRCYXNlTnVtYmVycyhrcCwgdGljay5kaXN0ID0gNTAwMDAwMCwgY2V4ID0gMC43KQojIEFkZCBkYXRhIGJhY2tncm91bmRzCmthcnlvcGxvdGVSOjprcERhdGFCYWNrZ3JvdW5kKGtwLCByMD0wLCByMSA9IDEsIGNvbG9yID0gIndoaXRlIikKIyBBZGQgYXhpcyBsYWJlbAprcEF4aXMoa3AsIHIwPTAuMywgcjEgPSAxLCBjZXggPSAwLjgpCiMgQWRkIGZkIGRhdGEKbHdkID0gMgprYXJ5b3Bsb3RlUjo6a3BMaW5lcyhrcCwKICAgICAgICAgICAgICAgICAgICAgY2hyID0gZGZfa3Akc2NhZmZvbGRbZGZfa3AkcDIgPT0gIkhOSSJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgeSA9IGRmX2twJG1lYW5fZmRbZGZfa3AkcDIgPT0gIkhOSSJdLAogICAgICAgICAgICAgICAgICAgICBjb2wgPSAiI0Y2NjczQSIsCiAgICAgICAgICAgICAgICAgICAgIHIwPTAuMywgcjEgPSAxLAogICAgICAgICAgICAgICAgICAgICBsd2QgPSBsd2QpCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjRjNCNjFGIiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEsCiAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IGx3ZCkKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIHggPSBkZl9rcCRtaWRbZGZfa3AkcDIgPT0gIkhTT0siXSwKICAgICAgICAgICAgICAgICAgICAgeSA9IGRmX2twJG1lYW5fZmRbZGZfa3AkcDIgPT0gIkhTT0siXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiM2MzFFNjgiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSwKICAgICAgICAgICAgICAgICAgICAgbHdkID0gbHdkKQojIEFkZCBTTlAgZGVuc2l0eSBkYXRhCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9bWlra19yYW5nZXMsIGNvbCA9ICIjNDlBMzc5IiwKICAgICAgICAgICAgICByMD0wLCByMT0wLjEsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9b2xfcmFuZ2VzX2xpc3QkaG5pLCBjb2wgPSAiI0Y2NjczQSIsCiAgICAgICAgICAgICAgcjA9MC4xLCByMT0wLjIsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9b2xfcmFuZ2VzX2xpc3QkaHNvaywgY29sID0gIiM2MzFFNjgiLCAKICAgICAgICAgICAgICByMD0wLjIsIHIxPTAuMywgCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCkKI2twUGxvdERlbnNpdHkoa3AsIGRhdGE9b2xfcmFuZ2VzX2xpc3QkaGRyciwgY29sID0gIiNGM0I2MUYiLAojICAgICAgICAgICAgICByMD0wLjQ1LCByMT0wLjYsCiMgICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCiMgQWRkIGV4b24gZGVuc2l0eSB0byBpZGVvZ3JhbQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPWV4X3JhbmdlcywgY29sID0gIiNmNzdjYjUiLAogICAgICAgICAgICAgIGRhdGEucGFuZWwgPSAiaWRlb2dyYW0iLAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDAsCiAgICAgICAgICAgICAgcjAgPSAwLjUsIHIxID0gMSkKa3BQbG90RGVuc2l0eShrcCwgZGF0YT1leF9yYW5nZXMsIGNvbCA9ICIjZjc3Y2I1IiwKICAgICAgICAgICAgICBkYXRhLnBhbmVsID0gImlkZW9ncmFtIiwKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwLAogICAgICAgICAgICAgIHIwID0gMC41LCByMSA9IDApCiMgQWRkIGxhYmVscwprcEFkZExhYmVscyhrcCwgbGFiZWxzPSJNSUtLIiwKICAgICAgICAgICAgcjA9MCwgcjE9MC4wNSwKICAgICAgICAgICAgbGFiZWwubWFyZ2luID0gMC4wMDEsCiAgICAgICAgICAgIGNleCA9IDAuNSkKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iSE5JIiwKICAgICAgICAgICAgcjA9MC4xLCByMT0wLjE1LCAKICAgICAgICAgICAgbGFiZWwubWFyZ2luID0gMC4wMDEsCiAgICAgICAgICAgIGNleCA9IDAuNSkKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iSFNPSyIsCiAgICAgICAgICAgIHIwPTAuMiwgcjE9MC4yNSwKICAgICAgICAgICAgbGFiZWwubWFyZ2luID0gMC4wMDEsCiAgICAgICAgICAgIGNleCA9IDAuNSkKCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9YnF1b3RlKGl0YWxpYyhmW2RdKSksCiAgICAgICAgICAgIHIwPTAuMywgcjE9MSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDM1LAogICAgICAgICAgICBjZXggPSAxKQpkZXYub2ZmKCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfZmlsZSkpCgpmaWxlLmNvcHkob3V0X2ZpbGUsIG5ld19wYXRoLCBvdmVyd3JpdGUgPSBUKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfZmlsZSkpCmBgYApVc2UgY2hyNAoKIyMjIENvbXBvc2UgZmluYWwgZmlndXJlCgpgYGB7cn0KYWJiYV9kaWFncmFtID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJhYmJhX2RpYWdyYW0ucG5nIikKdHJlZSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAidHJlZV9vcnl6aWFzX3dpdGhfYW5jZXN0b3IucG5nIikKa2FyeW9fY2hyNCA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiMjAyMTA0MDlfZmRfd2l0aF9kZW5zaXR5X2Nocl80XzUwMGtiLXdpbmRvdy5wbmciKQpjaXJjb3NfYWJiYSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiMjAyMTA0MDlfaW50cm9ncmVzc2lvbl9jaXJjb3NfTUlLS19BQkJBLnBuZyIpCgpmaW5hbF9hYmJhID0gZ2dkcmF3KCkgKwogIGRyYXdfaW1hZ2UodHJlZSwKICAgICAgICAgICAgeCA9IDAsIHkgPSAuNywgd2lkdGggPSAuNCwgaGVpZ2h0ID0gLjM1LCB2anVzdCA9IC4xLCBoanVzdCA9IC0uMSwgc2NhbGUgPSAxLjIpICsKICBkcmF3X2ltYWdlKGthcnlvX2NocjQsCiAgICAgICAgICAgICB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMC4zLCBzY2FsZSA9IDEuMikgKyAgCiAgZHJhd19pbWFnZShjaXJjb3NfYWJiYSwKICAgICAgICAgICAgIHggPSAuNCwgeSA9IC4zLCB3aWR0aCA9IC42LCBoZWlnaHQgPSAuNywgc2NhbGUgPSAxLjE1LCB2anVzdCA9IC4wMjUpICsKICBkcmF3X2ltYWdlKGFiYmFfZGlhZ3JhbSwKICAgICAgICAgIHggPSAwLCB5ID0gLjMsIHdpZHRoID0gLjQsIGhlaWdodCA9IC4zNSwgdmp1c3QgPSAtLjA1LCBzY2FsZSA9IDEuMSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoIkEiLCAiQiIsICJDIiwgIkQiKSwgc2l6ZSA9IDI1LAogICAgICAgICAgICAgICAgICB4ID0gYygwLCAwLCAuNDUsIDApLCB5ID0gYygxLCAuNywgMSwgLjMpLCBjb2xvciA9ICIjNGYwOTQzIikgIAoKCmZpbmFsX2FiYmEKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9Cmdnc2F2ZShoZXJlOjpoZXJlKHBsb3RzX2RpciwgIjIwMjEwNDA5X2ludHJvZ3Jlc3Npb25fZmluYWxfZmlndXJlLnBuZyIpLAogICAgICAgd2lkdGggPSAzNSwKICAgICAgIGhlaWdodCA9IDIxLjg3NSwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgo=